From e5278104112eb95527d6ffdf3a375b9fb390b5a4 Mon Sep 17 00:00:00 2001
From: Ivan Olenichev <>
Date: Mon, 28 Jun 2021 22:19:54 +0600
Subject: [PATCH] USG firmware update
---
Downstream/.cproject | 312 ++++++
Downstream/.gitignore | 2 +
Downstream/.project | 26 +
Downstream/.settings/language.settings.xml | 25 +
.../org.eclipse.cdt.codan.core.prefs | 71 ++
.../org.eclipse.cdt.managedbuilder.core.prefs | 21 +
Downstream/Downstream Debug OCD STLink.launch | 64 ++
Downstream/Downstream Debug.launch | 64 ++
Downstream/Downstream Release.launch | 64 ++
Downstream/Inc/board_config.h | 61 ++
Downstream/Inc/build_config.h | 29 +
Downstream/Inc/downstream_hid.h | 70 ++
Downstream/Inc/downstream_interface_def.h | 77 ++
Downstream/Inc/downstream_msc.h | 36 +
Downstream/Inc/downstream_spi.h | 84 ++
Downstream/Inc/downstream_statemachine.h | 54 +
Downstream/Inc/hal_config.h | 423 ++++++++
Downstream/Inc/interrupts.h | 72 ++
Downstream/Inc/led.h | 47 +
Downstream/Inc/usb_host.h | 66 ++
Downstream/Inc/usbh_config.h | 179 ++++
.../Class/HID/Inc/usbh_hid.h | 362 +++++++
.../Class/HID/Inc/usbh_hid_keybd.h | 326 ++++++
.../Class/HID/Inc/usbh_hid_mouse.h | 125 +++
.../Class/HID/Inc/usbh_hid_parser.h | 106 ++
.../Class/HID/Inc/usbh_hid_usage.h | 200 ++++
.../Class/HID/Src/usbh_hid.c | 850 ++++++++++++++++
.../Class/MSC/Inc/usbh_msc.h | 241 +++++
.../Class/MSC/Inc/usbh_msc_bot.h | 249 +++++
.../Class/MSC/Inc/usbh_msc_scsi.h | 232 +++++
.../Class/MSC/Src/usbh_msc.c | 892 ++++++++++++++++
.../Class/MSC/Src/usbh_msc_bot.c | 737 ++++++++++++++
.../Class/MSC/Src/usbh_msc_scsi.c | 473 +++++++++
.../Core/Inc/usbh_core.h | 170 ++++
.../Core/Inc/usbh_ctlreq.h | 159 +++
.../Core/Inc/usbh_def.h | 503 +++++++++
.../Core/Inc/usbh_ioreq.h | 168 +++
.../Core/Inc/usbh_pipes.h | 131 +++
.../Core/Src/usbh_conf_template.c | 271 +++++
.../Core/Src/usbh_core.c | 962 ++++++++++++++++++
.../Core/Src/usbh_ctlreq.c | 870 ++++++++++++++++
.../Core/Src/usbh_ioreq.c | 358 +++++++
.../Core/Src/usbh_pipes.c | 205 ++++
Downstream/Src/downstream_hid.c | 451 ++++++++
Downstream/Src/downstream_msc.c | 358 +++++++
Downstream/Src/downstream_spi.c | 419 ++++++++
Downstream/Src/downstream_statemachine.c | 338 ++++++
Downstream/Src/hal_msp.c | 163 +++
Downstream/Src/interrupts.c | 117 +++
Downstream/Src/led.c | 142 +++
Downstream/Src/main.c | 286 ++++++
Downstream/Src/usb_host.c | 88 ++
Downstream/Src/usbh_config.c | 470 +++++++++
Downstream/gcc_arm_stm32f401.ld | 115 +++
54 files changed, 13384 insertions(+)
create mode 100644 Downstream/.cproject
create mode 100644 Downstream/.gitignore
create mode 100644 Downstream/.project
create mode 100644 Downstream/.settings/language.settings.xml
create mode 100644 Downstream/.settings/org.eclipse.cdt.codan.core.prefs
create mode 100644 Downstream/.settings/org.eclipse.cdt.managedbuilder.core.prefs
create mode 100644 Downstream/Downstream Debug OCD STLink.launch
create mode 100644 Downstream/Downstream Debug.launch
create mode 100644 Downstream/Downstream Release.launch
create mode 100644 Downstream/Inc/board_config.h
create mode 100644 Downstream/Inc/build_config.h
create mode 100644 Downstream/Inc/downstream_hid.h
create mode 100644 Downstream/Inc/downstream_interface_def.h
create mode 100644 Downstream/Inc/downstream_msc.h
create mode 100644 Downstream/Inc/downstream_spi.h
create mode 100644 Downstream/Inc/downstream_statemachine.h
create mode 100644 Downstream/Inc/hal_config.h
create mode 100644 Downstream/Inc/interrupts.h
create mode 100644 Downstream/Inc/led.h
create mode 100644 Downstream/Inc/usb_host.h
create mode 100644 Downstream/Inc/usbh_config.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_keybd.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_mouse.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_parser.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_usage.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_core.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_conf_template.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ioreq.c
create mode 100644 Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c
create mode 100644 Downstream/Src/downstream_hid.c
create mode 100644 Downstream/Src/downstream_msc.c
create mode 100644 Downstream/Src/downstream_spi.c
create mode 100644 Downstream/Src/downstream_statemachine.c
create mode 100644 Downstream/Src/hal_msp.c
create mode 100644 Downstream/Src/interrupts.c
create mode 100644 Downstream/Src/led.c
create mode 100644 Downstream/Src/main.c
create mode 100644 Downstream/Src/usb_host.c
create mode 100644 Downstream/Src/usbh_config.c
create mode 100644 Downstream/gcc_arm_stm32f401.ld
diff --git a/Downstream/.cproject b/Downstream/.cproject
new file mode 100644
index 0000000..3c70d1b
--- /dev/null
+++ b/Downstream/.cproject
@@ -0,0 +1,312 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Downstream/.gitignore b/Downstream/.gitignore
new file mode 100644
index 0000000..ac01e66
--- /dev/null
+++ b/Downstream/.gitignore
@@ -0,0 +1,2 @@
+/Debug/
+/Release/
diff --git a/Downstream/.project b/Downstream/.project
new file mode 100644
index 0000000..d053b40
--- /dev/null
+++ b/Downstream/.project
@@ -0,0 +1,26 @@
+
+
+ Downstream
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/Downstream/.settings/language.settings.xml b/Downstream/.settings/language.settings.xml
new file mode 100644
index 0000000..855a758
--- /dev/null
+++ b/Downstream/.settings/language.settings.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Downstream/.settings/org.eclipse.cdt.codan.core.prefs b/Downstream/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 0000000..ff135cf
--- /dev/null
+++ b/Downstream/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,71 @@
+eclipse.preferences.version=1
+org.eclipse.cdt.codan.checkers.errnoreturn=Warning
+org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
+org.eclipse.cdt.codan.checkers.errreturnvalue=Error
+org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.nocommentinside=-Error
+org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.nolinecomment=-Error
+org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.noreturn=Error
+org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
+org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
+org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
+org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
diff --git a/Downstream/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/Downstream/.settings/org.eclipse.cdt.managedbuilder.core.prefs
new file mode 100644
index 0000000..3c47024
--- /dev/null
+++ b/Downstream/.settings/org.eclipse.cdt.managedbuilder.core.prefs
@@ -0,0 +1,21 @@
+eclipse.preferences.version=1
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/CPATH/delimiter=\:
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/CPATH/operation=remove
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/C_INCLUDE_PATH/delimiter=\:
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/C_INCLUDE_PATH/operation=remove
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/append=true
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/appendContributed=true
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/CPATH/delimiter=\:
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/CPATH/operation=remove
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/C_INCLUDE_PATH/delimiter=\:
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/C_INCLUDE_PATH/operation=remove
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/append=true
+environment/buildEnvironmentInclude/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/appendContributed=true
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/LIBRARY_PATH/delimiter=\:
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/LIBRARY_PATH/operation=remove
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/append=true
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.110983800/appendContributed=true
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/LIBRARY_PATH/delimiter=\:
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/LIBRARY_PATH/operation=remove
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/append=true
+environment/buildEnvironmentLibrary/ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.1300395207/appendContributed=true
diff --git a/Downstream/Downstream Debug OCD STLink.launch b/Downstream/Downstream Debug OCD STLink.launch
new file mode 100644
index 0000000..4c08dde
--- /dev/null
+++ b/Downstream/Downstream Debug OCD STLink.launch
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Downstream/Downstream Debug.launch b/Downstream/Downstream Debug.launch
new file mode 100644
index 0000000..13d08c4
--- /dev/null
+++ b/Downstream/Downstream Debug.launch
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Downstream/Downstream Release.launch b/Downstream/Downstream Release.launch
new file mode 100644
index 0000000..7b86390
--- /dev/null
+++ b/Downstream/Downstream Release.launch
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Downstream/Inc/board_config.h b/Downstream/Inc/board_config.h
new file mode 100644
index 0000000..cb27120
--- /dev/null
+++ b/Downstream/Inc/board_config.h
@@ -0,0 +1,61 @@
+/*
+ * board_config.h
+ *
+ * Created on: 25/03/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+#ifndef INC_BOARD_CONFIG_H_
+#define INC_BOARD_CONFIG_H_
+
+
+#define BSRR_SHIFT_HIGH 0
+#define BSRR_SHIFT_LOW 16
+
+#define PA_JTMS GPIO_PIN_13
+#define PA_JTCK GPIO_PIN_14
+#define PA_JTDI GPIO_PIN_15
+#define PB_JTDO GPIO_PIN_3
+#define PB_NJTRST GPIO_PIN_4
+
+#define FAULT_LED_PIN GPIO_PIN_13
+#define FAULT_LED_PORT GPIOC
+#define FAULT_LED_ON (FAULT_LED_PORT->BSRR = (FAULT_LED_PIN << BSRR_SHIFT_LOW)) //Fault LED is active-low
+#define FAULT_LED_OFF (FAULT_LED_PORT->BSRR = (FAULT_LED_PIN << BSRR_SHIFT_HIGH))
+
+#define H405_FAULT_LED_PIN GPIO_PIN_12 //Fault LED on Olimex H405 board
+#define H405_FAULT_LED_ON (FAULT_LED_PORT->BSRR = (H405_FAULT_LED_PIN << BSRR_SHIFT_LOW))
+
+#define INT_ACTIVE_PIN GPIO_PIN_2 //Temporary indicator of SPI (or whatever) activity
+#define INT_ACTIVE_PORT GPIOA
+#define INT_ACTIVE_ON INT_ACTIVE_PORT->BSRR = (INT_ACTIVE_PIN << BSRR_SHIFT_HIGH)
+#define INT_ACTIVE_OFF INT_ACTIVE_PORT->BSRR = (INT_ACTIVE_PIN << BSRR_SHIFT_LOW)
+
+//#define SPI1_NSS_PIN GPIO_PIN_4
+//#define SPI1_NSS_PORT GPIOA
+
+#define UPSTREAM_TX_REQUEST_PIN GPIO_PIN_3
+#define UPSTREAM_TX_REQUEST_PORT GPIOA
+#define UPSTREAM_TX_REQUEST_ASSERT (UPSTREAM_TX_REQUEST_PORT->BSRR = (UPSTREAM_TX_REQUEST_PIN << BSRR_SHIFT_LOW))
+#define UPSTREAM_TX_REQUEST_DEASSERT (UPSTREAM_TX_REQUEST_PORT->BSRR = (UPSTREAM_TX_REQUEST_PIN << BSRR_SHIFT_HIGH))
+
+#define DBGMCU_IDCODE_DEV_ID_405_407_415_417 0x413
+#define DBGMCU_IDCODE_DEV_ID_401xB_xC 0x423
+
+#define BOARD_REV_PIN_MASK 0xE000
+#define BOARD_ID_PIN_MASK 0x1000
+#define BOARD_REV_ID_PORT GPIOB
+
+#define BOARD_REV_1_0_BETA 0
+#define BOARD_REV_1_0_BETA_3 1
+
+#define BOARD_REV_1_0_BETA_FREQ 8
+#define BOARD_REV_1_0_BETA_3_FREQ 16
+
+
+#endif /* INC_BOARD_CONFIG_H_ */
diff --git a/Downstream/Inc/build_config.h b/Downstream/Inc/build_config.h
new file mode 100644
index 0000000..fe59f08
--- /dev/null
+++ b/Downstream/Inc/build_config.h
@@ -0,0 +1,29 @@
+/*
+ * build_config.h
+ *
+ * Created on: Jun 20, 2017
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_BUILD_CONFIG_H_
+#define INC_BUILD_CONFIG_H_
+
+
+#define CONFIG_MASS_STORAGE_ENABLED
+#define CONFIG_MASS_STORAGE_WRITES_PERMITTED
+
+#define CONFIG_KEYBOARD_ENABLED
+#define CONFIG_MOUSE_ENABLED
+
+#define CONFIG_READ_FLASH_TIME_MS 3000 //Enable read LED flashes for the specified length of time
+
+#define CONFIG_USB_ID_ENABLED
+
+#define CONFIG_FLASH_RDP_ENABLE
+
+
+#endif /* INC_BUILD_CONFIG_H_ */
diff --git a/Downstream/Inc/downstream_hid.h b/Downstream/Inc/downstream_hid.h
new file mode 100644
index 0000000..bd559cf
--- /dev/null
+++ b/Downstream/Inc/downstream_hid.h
@@ -0,0 +1,70 @@
+/*
+ * downstream_hid.h
+ *
+ * Created on: Apr 10, 2016
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_DOWNSTREAM_HID_H_
+#define INC_DOWNSTREAM_HID_H_
+
+
+#include "downstream_interface_def.h"
+#include "downstream_spi.h"
+#include "usbh_def.h"
+
+
+#define HID_MAX_REPORT_LEN 8
+
+//These defines are duplicated in upstream_hid.h. Keep them in sync!
+#define HID_MOUSE_INPUT_DATA_LEN 4
+#define HID_MOUSE_OUTPUT_DATA_LEN 0
+#define HID_MOUSE_MAX_BUTTONS 3
+
+#define HID_KEYBOARD_INPUT_DATA_LEN 8
+#define HID_KEYBOARD_OUTPUT_DATA_LEN 1
+#define HID_KEYBOARD_MAX_KEY 101 //Also set in Upstream's HID report descriptor
+#define HID_KEYBOARD_MAX_LED 3
+
+
+//Stuff for parsing HID descriptors:
+#define HID_ITEM_LONG 0xFC
+#define HID_ITEM_MASK 0xFC
+#define HID_ITEM_LENGTH_MASK 0x03
+
+#define HID_ITEM_USAGE_PAGE 0x04 //'global' usage page
+#define HID_ITEM_USAGE_PAGE_BUTTON 0x09
+#define HID_ITEM_USAGE_PAGE_DESKTOP 0x01
+
+#define HID_ITEM_COLLECTION 0xA0
+#define HID_ITEM_COLLECTION_PHYS 0x00
+#define HID_ITEM_END_COLLECTION 0xC0
+
+#define HID_ITEM_USAGE 0x08 //'local' usage
+#define HID_ITEM_USAGE_X 0x30
+#define HID_ITEM_USAGE_Y 0x31
+#define HID_ITEM_USAGE_WHEEL 0x38
+
+#define HID_ITEM_REPORT_SIZE 0x74 //'global' report size
+#define HID_ITEM_REPORT_COUNT 0x94 //'global' report count
+#define HID_ITEM_REPORT_ID 0x84
+
+#define HID_ITEM_INPUT 0x80 //'main' input
+#define HID_ITEM_INPUT_ABS 0x02
+#define HID_ITEM_INPUT_REL 0x06
+
+
+typedef void (*TransactionCompleteCallbackTypeDef)(USBH_StatusTypeDef result);
+
+InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void);
+void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
+void Downstream_HID_InterruptReportCallback(USBH_StatusTypeDef result);
+void Downstream_HID_SendReportCallback(USBH_StatusTypeDef result);
+
+
+
+#endif /* INC_DOWNSTREAM_HID_H_ */
diff --git a/Downstream/Inc/downstream_interface_def.h b/Downstream/Inc/downstream_interface_def.h
new file mode 100644
index 0000000..eec61a8
--- /dev/null
+++ b/Downstream/Inc/downstream_interface_def.h
@@ -0,0 +1,77 @@
+/*
+ * downstream_interface_def.h
+ *
+ * Created on: 24/07/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_DOWNSTREAM_INTERFACE_DEF_H_
+#define INC_DOWNSTREAM_INTERFACE_DEF_H_
+
+
+//***************
+// Attention!
+// Keep this file synchronised with upstream_interface_def.h
+// in the Upstream project.
+//***************
+
+
+
+#define COMMAND_CLASS_DATA_FLAG 0x80
+#define COMMAND_CLASS_MASK ((uint8_t)(~COMMAND_CLASS_DATA_FLAG))
+
+
+typedef enum
+{
+ COMMAND_CLASS_INTERFACE,
+ COMMAND_CLASS_MASS_STORAGE,
+ COMMAND_CLASS_HID_MOUSE,
+ COMMAND_CLASS_HID_KEYBOARD,
+ //...
+ COMMAND_CLASS_ERROR
+}
+InterfaceCommandClassTypeDef;
+
+
+typedef enum
+{
+ COMMAND_INTERFACE_ECHO, //Returns echo packet including all data
+ COMMAND_INTERFACE_NOTIFY_DEVICE //Returns COMMAND_CLASS_*** byte when downstream USB device is connected
+}
+InterfaceCommandInterfaceTypeDef;
+
+
+typedef enum
+{
+ COMMAND_MSC_TEST_UNIT_READY, //Returns HAL_StatusTypeDef result
+ COMMAND_MSC_GET_CAPACITY, //Returns uint32_t blk_nbr, uint32_t blk_size
+ COMMAND_MSC_READ, //Returns data stream or error packet
+ COMMAND_MSC_WRITE, //Waits for data stream or returns error packet
+ COMMAND_MSC_DISCONNECT, //Returns same packet after sending Stop command to device
+ COMMAND_MSC_POLL_DISCONNECT //Returns same packet if device is still connected
+}
+InterfaceCommandMscTypeDef;
+
+
+typedef enum
+{
+ COMMAND_HID_GET_REPORT, //Returns HID report from device
+ COMMAND_HID_SET_REPORT //Sends HID report to device. Simple ack packet contains no data.
+}
+InterfaceCommandHidTypeDef;
+
+
+typedef enum
+{
+ COMMAND_ERROR_GENERIC, //Something went wrong, time to FREAKOUT
+ COMMAND_ERROR_DEVICE_DISCONNECTED, //Device unexpectedly disconnected
+}
+InterfaceCommandErrorTypeDef;
+
+
+
+#endif /* INC_DOWNSTREAM_INTERFACE_DEF_H_ */
diff --git a/Downstream/Inc/downstream_msc.h b/Downstream/Inc/downstream_msc.h
new file mode 100644
index 0000000..d78c226
--- /dev/null
+++ b/Downstream/Inc/downstream_msc.h
@@ -0,0 +1,36 @@
+/*
+ * downstream_msc.h
+ *
+ * Created on: 8/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_DOWNSTREAM_MSC_H_
+#define INC_DOWNSTREAM_MSC_H_
+
+
+#include "downstream_interface_def.h"
+#include "downstream_spi.h"
+
+
+#define MSC_SUPPORTED_BLOCK_SIZE 512
+#define MSC_FIXED_LUN 0
+
+
+typedef void (*DownstreamMSCCallbackPacketTypeDef)(DownstreamPacketTypeDef* receivedPacket,
+ uint16_t dataLength8);
+
+
+InterfaceCommandClassTypeDef Downstream_MSC_ApproveConnectedDevice(void);
+void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
+HAL_StatusTypeDef Downstream_MSC_PutStreamDataPacket(DownstreamPacketTypeDef* packetToSend,
+ uint32_t dataLength8);
+HAL_StatusTypeDef Downstream_MSC_GetStreamDataPacket(DownstreamMSCCallbackPacketTypeDef callback);
+
+
+
+#endif /* INC_DOWNSTREAM_MSC_H_ */
diff --git a/Downstream/Inc/downstream_spi.h b/Downstream/Inc/downstream_spi.h
new file mode 100644
index 0000000..6f59a6f
--- /dev/null
+++ b/Downstream/Inc/downstream_spi.h
@@ -0,0 +1,84 @@
+/*
+ * downstream_spi.h
+ *
+ * Created on: 24/07/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_DOWNSTREAM_SPI_H_
+#define INC_DOWNSTREAM_SPI_H_
+
+
+#include "usbh_config.h"
+
+
+#define DOWNSTREAM_PACKET_HEADER_LEN (2) //Min length = CommandClass & Command bytes
+#define DOWNSTREAM_PACKET_LEN (DOWNSTREAM_PACKET_HEADER_LEN + BOT_PAGE_LENGTH)
+#define DOWNSTREAM_PACKET_LEN_MIN (DOWNSTREAM_PACKET_HEADER_LEN)
+
+#define DOWNSTREAM_PACKET_HEADER_LEN_16 (DOWNSTREAM_PACKET_HEADER_LEN / 2)
+#define DOWNSTREAM_PACKET_LEN_16 (DOWNSTREAM_PACKET_LEN / 2)
+#define DOWNSTREAM_PACKET_LEN_MIN_16 (DOWNSTREAM_PACKET_LEN_MIN / 2)
+
+#define DOWNSTREAM_SPI_FREAKOUT \
+ do { \
+ Downstream_PacketProcessor_FreakOut(); \
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_ERROR; \
+ while (1); \
+ } while (0);
+
+
+
+typedef enum
+{
+ DOWNSTREAM_INTERFACE_IDLE,
+ DOWNSTREAM_INTERFACE_RX_SIZE_WAIT,
+ DOWNSTREAM_INTERFACE_RX_PACKET_WAIT,
+ DOWNSTREAM_INTERFACE_TX_SIZE_WAIT,
+ DOWNSTREAM_INTERFACE_TX_PACKET_WAIT,
+ DOWNSTREAM_INTERFACE_ERROR
+}
+InterfaceStateTypeDef;
+
+
+typedef enum
+{
+ NOT_BUSY,
+ BUSY
+}
+PacketBusyTypeDef;
+
+
+typedef struct
+{
+ PacketBusyTypeDef Busy; //Everything after Busy should be word-aligned
+ uint16_t Length16 __ALIGN_END; //Packet length includes CommandClass, Command, and Data
+ uint8_t CommandClass;
+ uint8_t Command;
+ uint8_t Data[BOT_PAGE_LENGTH]; //Should (must?) be word-aligned, for USB copy routine
+}
+DownstreamPacketTypeDef;
+
+
+
+typedef void (*FreePacketCallbackTypeDef)(DownstreamPacketTypeDef* freePacket);
+typedef void (*SpiPacketReceivedCallbackTypeDef)(DownstreamPacketTypeDef* receivedPacket);
+
+
+void Downstream_InitSPI(void);
+HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback);
+DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void);
+void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease);
+HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback);
+HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite);
+void Downstream_SPIProcess(void);
+
+void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
+void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
+
+
+#endif /* INC_DOWNSTREAM_SPI_H_ */
diff --git a/Downstream/Inc/downstream_statemachine.h b/Downstream/Inc/downstream_statemachine.h
new file mode 100644
index 0000000..deff744
--- /dev/null
+++ b/Downstream/Inc/downstream_statemachine.h
@@ -0,0 +1,54 @@
+/*
+ * downstream_statemachine.h
+ *
+ * Created on: 2/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_DOWNSTREAM_STATEMACHINE_H_
+#define INC_DOWNSTREAM_STATEMACHINE_H_
+
+
+#include "usbh_def.h"
+#include "usb_host.h"
+#include "downstream_spi.h"
+
+
+typedef enum
+{
+ STATE_DEVICE_NOT_READY,
+ STATE_DEVICE_READY, //Go here if HOST_USER_CLASS_ACTIVE callback arrives first
+ STATE_WAIT_DEVICE_READY, //Go here if COMMAND_INTERFACE_NOTIFY_DEVICE message arrives first
+ STATE_ACTIVE,
+ STATE_ERROR
+} DownstreamStateTypeDef;
+
+
+
+#define DOWNSTREAM_STATEMACHINE_FREAKOUT \
+ do { \
+ USB_Host_Disconnect(); \
+ LED_SetState(LED_STATUS_FLASH_ERROR); \
+ /*DownstreamState = STATE_ERROR; */ \
+ while (1); \
+} while (0);
+
+
+
+
+void Downstream_InitStateMachine(void);
+void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id);
+void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
+void Downstream_PacketProcessor_GenericErrorReply(DownstreamPacketTypeDef* replyPacket);
+void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket);
+void Downstream_PacketProcessor_NotifyDisconnectReplyRequired(void);
+void Downstream_PacketProcessor_CheckNotifyDisconnectReply(void);
+void Downstream_PacketProcessor_SetErrorState(void);
+void Downstream_PacketProcessor_FreakOut(void);
+
+
+#endif /* INC_DOWNSTREAM_STATEMACHINE_H_ */
diff --git a/Downstream/Inc/hal_config.h b/Downstream/Inc/hal_config.h
new file mode 100644
index 0000000..18ea4ab
--- /dev/null
+++ b/Downstream/Inc/hal_config.h
@@ -0,0 +1,423 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ *
© COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+
+//#define HAL_ADC_MODULE_ENABLED
+//#define HAL_CAN_MODULE_ENABLED
+//#define HAL_CRC_MODULE_ENABLED
+//#define HAL_CRYP_MODULE_ENABLED
+//#define HAL_DAC_MODULE_ENABLED
+//#define HAL_DCMI_MODULE_ENABLED
+//#define HAL_DMA2D_MODULE_ENABLED
+//#define HAL_ETH_MODULE_ENABLED
+//#define HAL_NAND_MODULE_ENABLED
+//#define HAL_NOR_MODULE_ENABLED
+//#define HAL_PCCARD_MODULE_ENABLED
+//#define HAL_SRAM_MODULE_ENABLED
+//#define HAL_SDRAM_MODULE_ENABLED
+//#define HAL_HASH_MODULE_ENABLED
+//#define HAL_I2C_MODULE_ENABLED
+//#define HAL_I2S_MODULE_ENABLED
+//#define HAL_IWDG_MODULE_ENABLED
+//#define HAL_LTDC_MODULE_ENABLED
+//#define HAL_RNG_MODULE_ENABLED
+//#define HAL_RTC_MODULE_ENABLED
+//#define HAL_SAI_MODULE_ENABLED
+//#define HAL_SD_MODULE_ENABLED
+#define HAL_SPI_MODULE_ENABLED
+//#define HAL_TIM_MODULE_ENABLED
+//#define HAL_UART_MODULE_ENABLED
+//#define HAL_USART_MODULE_ENABLED
+//#define HAL_IRDA_MODULE_ENABLED
+//#define HAL_SMARTCARD_MODULE_ENABLED
+//#define HAL_WWDG_MODULE_ENABLED
+//#define HAL_PCD_MODULE_ENABLED
+#define HAL_HCD_MODULE_ENABLED
+//#define HAL_QSPI_MODULE_ENABLED
+//#define HAL_QSPI_MODULE_ENABLED
+//#define HAL_CEC_MODULE_ENABLED
+//#define HAL_FMPI2C_MODULE_ENABLED
+//#define HAL_SPDIFRX_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## HSE/HSI Values adaptation ##################### */
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+ #define LSI_VALUE ((uint32_t)32000)
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */
+#endif /* LSE_VALUE */
+
+/**
+ * @brief External clock source for I2S peripheral
+ * This value is used by the I2S HAL module to compute the I2S clock source
+ * frequency, this source is inserted directly through I2S_CKIN pad.
+ */
+#if !defined (EXTERNAL_CLOCK_VALUE)
+ #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the External audio frequency in Hz*/
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+
+#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((uint32_t)0) /*!< tick interrupt priority */
+#define USE_RTOS 0
+#define PREFETCH_ENABLE 1
+#define INSTRUCTION_CACHE_ENABLE 1
+#define DATA_CACHE_ENABLE 1
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1 */
+
+/* ################## Ethernet peripheral configuration ##################### */
+
+/* Section 1 : Ethernet peripheral configuration */
+
+/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
+#define MAC_ADDR0 2
+#define MAC_ADDR1 0
+#define MAC_ADDR2 0
+#define MAC_ADDR3 0
+#define MAC_ADDR4 0
+#define MAC_ADDR5 0
+
+/* Definition of the Ethernet driver buffers size and count */
+#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
+#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
+#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#define PHY_READ_TO ((uint32_t)0x0000FFFF)
+#define PHY_WRITE_TO ((uint32_t)0x0000FFFF)
+
+/* Section 3: Common PHY Registers */
+
+#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */
+#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */
+
+#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
+#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
+#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
+#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
+#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
+#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
+#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
+#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
+#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
+#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
+
+#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
+#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
+#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
+
+/* Section 4: Extended PHY Registers */
+
+#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */
+#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */
+#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */
+
+#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */
+#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */
+#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */
+
+#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */
+#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */
+
+#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */
+#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32f4xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_FMPI2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_fmpi2c.h"
+#endif /* HAL_FMPI2C_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+ #include "stm32f4xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Inc/interrupts.h b/Downstream/Inc/interrupts.h
new file mode 100644
index 0000000..35e9584
--- /dev/null
+++ b/Downstream/Inc/interrupts.h
@@ -0,0 +1,72 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_it.h
+ * @brief This file contains the headers of the interrupt handlers.
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_IT_H
+#define __STM32F4xx_IT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define INT_PRIORITY_SYSTICK 2
+#define INT_PRIORITY_SPI_DMA 10
+//#define INT_PRIORITY_SPI 8 //Interrupt-based SPI must be highest priority!
+#define INT_PRIORITY_USB 10
+
+
+ /* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+void SysTick_Handler(void);
+void DMA2_Stream2_IRQHandler(void);
+void DMA2_Stream3_IRQHandler(void);
+void OTG_FS_IRQHandler(void);
+void BusFault_Handler(void);
+
+void EnableOneBusFault(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_IT_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Inc/led.h b/Downstream/Inc/led.h
new file mode 100644
index 0000000..b79fc91
--- /dev/null
+++ b/Downstream/Inc/led.h
@@ -0,0 +1,47 @@
+/*
+ * led.h
+ *
+ * Created on: 19/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INC_LED_H_
+#define INC_LED_H_
+
+
+#include "stm32f4xx_hal.h"
+
+
+typedef enum
+{
+ LED_STATUS_STARTUP,
+ LED_STATUS_OFF,
+ LED_STATUS_FLASH_ERROR,
+ LED_STATUS_FLASH_UNSUPPORTED,
+ LED_STATUS_FLASH_BOTDETECT,
+ LED_STATUS_FLASH_READWRITE
+}
+LedStatusTypeDef;
+
+
+void LED_Init(void);
+void LED_SetState(LedStatusTypeDef newState);
+void LED_Tick(void);
+
+
+#define STARTUP_FLASH_DELAY_MS 500
+
+#define LED_ERROR_BLINK_MS 100
+#define LED_UNSUPPORTED_BLINK_MS 500
+#define LED_BOTDETECT_ON_MS 100
+#define LED_BOTDETECT_OFF_MS (1000 - (LED_BOTDETECT_ON_MS * 3)) //Two flashes, total period = 1 sec
+#define LED_READWRITE_ON_MS 10
+#define LED_READWRITE_OFF_MS 30
+
+
+
+#endif /* INC_LED_H_ */
diff --git a/Downstream/Inc/usb_host.h b/Downstream/Inc/usb_host.h
new file mode 100644
index 0000000..c07de96
--- /dev/null
+++ b/Downstream/Inc/usb_host.h
@@ -0,0 +1,66 @@
+/**
+ ******************************************************************************
+ * @file : USB_HOST
+ * @version : v1.0_Cube
+ * @brief : Header for usb_host file.
+ ******************************************************************************
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __usb_host_H
+#define __usb_host_H
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx.h"
+#include "stm32f4xx_hal.h"
+
+
+void USB_Host_Init(void);
+void USB_Host_Process(void);
+void USB_Host_Disconnect(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__usb_host_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Inc/usbh_config.h b/Downstream/Inc/usbh_config.h
new file mode 100644
index 0000000..96f98eb
--- /dev/null
+++ b/Downstream/Inc/usbh_config.h
@@ -0,0 +1,179 @@
+/**
+ ******************************************************************************
+ * @file : usbh_conf.h
+ * @version : v1.0_Cube
+ * @brief : Header for usbh_conf file.
+ ******************************************************************************
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+*/
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBH_CONF__H__
+#define __USBH_CONF__H__
+#include
+#include
+#include
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx.h"
+#include "stm32f4xx_hal.h"
+
+/**
+ MiddleWare name : USB_HOST
+ MiddleWare fileName : usbh_conf.h
+ MiddleWare version :
+*/
+/*---------- -----------*/
+#define USBH_MAX_NUM_ENDPOINTS 2
+
+/*---------- -----------*/
+#define USBH_MAX_NUM_INTERFACES 3
+
+/*---------- -----------*/
+#define USBH_MAX_NUM_CONFIGURATION 1
+
+/*---------- -----------*/
+#define USBH_KEEP_CFG_DESCRIPTOR 0
+
+/*---------- -----------*/
+#define USBH_MAX_NUM_SUPPORTED_CLASS 2
+
+/*---------- -----------*/
+#define USBH_MAX_SIZE_CONFIGURATION 256
+
+/*---------- -----------*/
+#define USBH_MAX_DATA_BUFFER 256 //was 512, string descriptors are max 255 bytes
+
+/*---------- -----------*/
+#define USBH_DEBUG_LEVEL 0
+
+/*---------- -----------*/
+#define USBH_USE_OS 0
+
+
+#define BOT_PAGE_LENGTH 512 //Moved here from usbh_msc_bot.h to avoid a circular include loop :(
+
+
+/****************************************/
+/* #define for FS and HS identification */
+#define HOST_HS 0
+#define HOST_FS 1
+
+/** @defgroup USBH_Exported_Macros
+ * @{
+ */
+#if (USBH_USE_OS == 1)
+ #include "cmsis_os.h"
+ #define USBH_PROCESS_PRIO osPriorityNormal
+ #define USBH_PROCESS_STACK_SIZE ((uint16_t)0)
+#endif
+
+ /* Memory management macros */
+#define USBH_malloc malloc
+#define USBH_free free
+#define USBH_memset memset
+#define USBH_memcpy memcpy
+
+ /* DEBUG macros */
+
+#if (USBH_DEBUG_LEVEL > 0)
+#define USBH_UsrLog(...) printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_UsrLog(...)
+#endif
+
+
+#if (USBH_DEBUG_LEVEL > 1)
+
+#define USBH_ErrLog(...) printf("ERROR: ") ;\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_ErrLog(...)
+#endif
+
+
+#if (USBH_DEBUG_LEVEL > 2)
+#define USBH_DbgLog(...) printf("DEBUG : ") ;\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_DbgLog(...)
+#endif
+
+/**
+ * @}
+ */
+
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_FunctionsPrototype
+ * @{
+ */
+/**
+ * @}
+ */
+
+#endif //__USBH_CONF__H__
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid.h
new file mode 100644
index 0000000..9cf0f8b
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid.h
@@ -0,0 +1,362 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid.h
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file contains all the prototypes for the usbh_hid.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ *
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_HID_H
+#define __USBH_HID_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "downstream_hid.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_CORE
+ * @brief This file is the Header file for usbh_hid.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_CORE_Exported_Types
+ * @{
+ */
+
+#define HID_MIN_POLL 10
+#define HID_MAX_REPORT_SIZE 8
+#define HID_REPORT_BUFFER_SIZE 64
+#define HID_MAX_USAGE 10
+#define HID_MAX_NBR_REPORT_FMT 10
+//#define HID_QUEUE_SIZE 10
+//
+//#define HID_ITEM_LONG 0xFE
+//
+//#define HID_ITEM_TYPE_MAIN 0x00
+//#define HID_ITEM_TYPE_GLOBAL 0x01
+//#define HID_ITEM_TYPE_LOCAL 0x02
+//#define HID_ITEM_TYPE_RESERVED 0x03
+//
+//
+//#define HID_MAIN_ITEM_TAG_INPUT 0x08
+//#define HID_MAIN_ITEM_TAG_OUTPUT 0x09
+//#define HID_MAIN_ITEM_TAG_COLLECTION 0x0A
+//#define HID_MAIN_ITEM_TAG_FEATURE 0x0B
+//#define HID_MAIN_ITEM_TAG_ENDCOLLECTION 0x0C
+//
+//
+//#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0x00
+//#define HID_GLOBAL_ITEM_TAG_LOG_MIN 0x01
+//#define HID_GLOBAL_ITEM_TAG_LOG_MAX 0x02
+//#define HID_GLOBAL_ITEM_TAG_PHY_MIN 0x03
+//#define HID_GLOBAL_ITEM_TAG_PHY_MAX 0x04
+//#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 0x05
+//#define HID_GLOBAL_ITEM_TAG_UNIT 0x06
+//#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 0x07
+//#define HID_GLOBAL_ITEM_TAG_REPORT_ID 0x08
+//#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 0x09
+//#define HID_GLOBAL_ITEM_TAG_PUSH 0x0A
+//#define HID_GLOBAL_ITEM_TAG_POP 0x0B
+//
+//
+//#define HID_LOCAL_ITEM_TAG_USAGE 0x00
+//#define HID_LOCAL_ITEM_TAG_USAGE_MIN 0x01
+//#define HID_LOCAL_ITEM_TAG_USAGE_MAX 0x02
+//#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 0x03
+//#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MIN 0x04
+//#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAX 0x05
+//#define HID_LOCAL_ITEM_TAG_STRING_INDEX 0x07
+//#define HID_LOCAL_ITEM_TAG_STRING_MIN 0x08
+//#define HID_LOCAL_ITEM_TAG_STRING_MAX 0x09
+//#define HID_LOCAL_ITEM_TAG_DELIMITER 0x0A
+
+
+#define HID_REPORT_DIRECTION_IN 0x01
+#define HID_REPORT_DIRECTION_OUT 0x02
+
+
+/* States for HID State Machine */
+typedef enum
+{
+ HID_INIT= 0,
+ HID_IDLE,
+ HID_GET_DATA,
+ HID_GET_POLL,
+ HID_SET_DATA_POLL,
+ HID_ERROR,
+}
+HID_StateTypeDef;
+
+typedef enum
+{
+ HID_REQ_INIT = 0,
+ HID_REQ_IDLE,
+ HID_REQ_GET_REPORT_DESC,
+ HID_REQ_GET_HID_DESC,
+ HID_REQ_SET_IDLE,
+ HID_REQ_SET_PROTOCOL,
+ HID_REQ_SET_REPORT,
+
+}
+HID_CtlStateTypeDef;
+
+typedef enum
+{
+ HID_MOUSE = 0x01,
+ HID_KEYBOARD = 0x02,
+ HID_UNKNOWN = 0xFF,
+}
+HID_TypeTypeDef;
+
+
+typedef struct _HID_ReportData
+{
+ uint8_t ReportID;
+ uint8_t ReportType;
+ uint16_t UsagePage;
+ uint32_t Usage[HID_MAX_USAGE];
+ uint32_t NbrUsage;
+ uint32_t UsageMin;
+ uint32_t UsageMax;
+ int32_t LogMin;
+ int32_t LogMax;
+ int32_t PhyMin;
+ int32_t PhyMax;
+ int32_t UnitExp;
+ uint32_t Unit;
+ uint32_t ReportSize;
+ uint32_t ReportCnt;
+ uint32_t Flag;
+ uint32_t PhyUsage;
+ uint32_t AppUsage;
+ uint32_t LogUsage;
+}
+HID_ReportDataTypeDef;
+
+typedef struct _HID_ReportIDTypeDef {
+ uint8_t Size; /* Report size return by the device id */
+ uint8_t ReportID; /* Report Id */
+ uint8_t Type; /* Report Type (INPUT/OUTPUT/FEATURE) */
+} HID_ReportIDTypeDef;
+
+typedef struct _HID_CollectionTypeDef
+{
+ uint32_t Usage;
+ uint8_t Type;
+ struct _HID_CollectionTypeDef *NextPtr;
+} HID_CollectionTypeDef;
+
+
+typedef struct _HID_AppCollectionTypeDef {
+ uint32_t Usage;
+ uint8_t Type;
+ uint8_t NbrReportFmt;
+ HID_ReportDataTypeDef ReportData[HID_MAX_NBR_REPORT_FMT];
+} HID_AppCollectionTypeDef;
+
+
+typedef struct _HIDDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdHID; /* indicates what endpoint this descriptor is describing */
+ uint8_t bCountryCode; /* specifies the transfer type. */
+ uint8_t bNumDescriptors; /* specifies the transfer type. */
+ uint8_t bReportDescriptorType; /* Maximum Packet Size this endpoint is capable of sending or receiving */
+ uint16_t wItemLength; /* is used to specify the polling interval of certain transfers. */
+}
+HID_DescTypeDef;
+
+
+typedef struct
+{
+ uint8_t *buf;
+ uint16_t head;
+ uint16_t tail;
+ uint16_t size;
+ uint8_t lock;
+} FIFO_TypeDef;
+
+
+
+/* Structure for HID process */
+typedef struct _HID_Process
+{
+ uint8_t OutPipe;
+ uint8_t InPipe;
+ uint8_t OutEp;
+ uint8_t InEp;
+ HID_StateTypeDef state;
+ HID_CtlStateTypeDef ctl_state;
+ uint16_t length;
+ uint16_t poll;
+ uint32_t timer;
+ uint8_t ep_addr;
+ uint8_t Protocol;
+ HID_DescTypeDef HID_Desc;
+ TransactionCompleteCallbackTypeDef ReportCallback;
+ uint8_t Data[HID_REPORT_BUFFER_SIZE];
+}
+HID_HandleTypeDef;
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Defines
+ * @{
+ */
+
+#define USB_HID_GET_REPORT 0x01
+#define USB_HID_GET_IDLE 0x02
+#define USB_HID_GET_PROTOCOL 0x03
+#define USB_HID_SET_REPORT 0x09
+#define USB_HID_SET_IDLE 0x0A
+#define USB_HID_SET_PROTOCOL 0x0B
+
+
+
+
+/* HID Class Codes */
+#define USB_HID_CLASS 0x03
+
+/* Interface Descriptor field values for HID Boot Protocol */
+#define HID_BOOT_CODE 0x01
+#define HID_KEYBRD_PROTOCOL 0x01
+#define HID_MOUSE_PROTOCOL 0x02
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef HID_Class;
+#define USBH_HID_CLASS &HID_Class
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen,
+ TransactionCompleteCallbackTypeDef callback);
+
+USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen);
+
+USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost,
+ uint8_t duration,
+ uint8_t reportId);
+
+USBH_StatusTypeDef USBH_HID_SetProtocol (USBH_HandleTypeDef *phost,
+ uint8_t protocol);
+
+void USBH_HID_EventCallback(USBH_HandleTypeDef *phost);
+
+HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost);
+
+uint8_t USBH_HID_GetPollInterval(USBH_HandleTypeDef *phost);
+
+void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size);
+
+uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes);
+
+uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes);
+
+HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost,
+ TransactionCompleteCallbackTypeDef callback);
+
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_HID_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_keybd.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_keybd.h
new file mode 100644
index 0000000..06de452
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_keybd.h
@@ -0,0 +1,326 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_keybd.h
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file contains all the prototypes for the usbh_hid_keybd.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive -----------------------------------------------*/
+#ifndef __USBH_HID_KEYBD_H
+#define __USBH_HID_KEYBD_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+#include "usbh_hid_keybd.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_KEYBD
+ * @brief This file is the Header file for usbh_hid_keybd.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_KEYBD_Exported_Types
+ * @{
+ */
+#define KEY_NONE 0x00
+#define KEY_ERRORROLLOVER 0x01
+#define KEY_POSTFAIL 0x02
+#define KEY_ERRORUNDEFINED 0x03
+#define KEY_A 0x04
+#define KEY_B 0x05
+#define KEY_C 0x06
+#define KEY_D 0x07
+#define KEY_E 0x08
+#define KEY_F 0x09
+#define KEY_G 0x0A
+#define KEY_H 0x0B
+#define KEY_I 0x0C
+#define KEY_J 0x0D
+#define KEY_K 0x0E
+#define KEY_L 0x0F
+#define KEY_M 0x10
+#define KEY_N 0x11
+#define KEY_O 0x12
+#define KEY_P 0x13
+#define KEY_Q 0x14
+#define KEY_R 0x15
+#define KEY_S 0x16
+#define KEY_T 0x17
+#define KEY_U 0x18
+#define KEY_V 0x19
+#define KEY_W 0x1A
+#define KEY_X 0x1B
+#define KEY_Y 0x1C
+#define KEY_Z 0x1D
+#define KEY_1_EXCLAMATION_MARK 0x1E
+#define KEY_2_AT 0x1F
+#define KEY_3_NUMBER_SIGN 0x20
+#define KEY_4_DOLLAR 0x21
+#define KEY_5_PERCENT 0x22
+#define KEY_6_CARET 0x23
+#define KEY_7_AMPERSAND 0x24
+#define KEY_8_ASTERISK 0x25
+#define KEY_9_OPARENTHESIS 0x26
+#define KEY_0_CPARENTHESIS 0x27
+#define KEY_ENTER 0x28
+#define KEY_ESCAPE 0x29
+#define KEY_BACKSPACE 0x2A
+#define KEY_TAB 0x2B
+#define KEY_SPACEBAR 0x2C
+#define KEY_MINUS_UNDERSCORE 0x2D
+#define KEY_EQUAL_PLUS 0x2E
+#define KEY_OBRACKET_AND_OBRACE 0x2F
+#define KEY_CBRACKET_AND_CBRACE 0x30
+#define KEY_BACKSLASH_VERTICAL_BAR 0x31
+#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32
+#define KEY_SEMICOLON_COLON 0x33
+#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34
+#define KEY_GRAVE ACCENT AND TILDE 0x35
+#define KEY_COMMA_AND_LESS 0x36
+#define KEY_DOT_GREATER 0x37
+#define KEY_SLASH_QUESTION 0x38
+#define KEY_CAPS LOCK 0x39
+#define KEY_F1 0x3A
+#define KEY_F2 0x3B
+#define KEY_F3 0x3C
+#define KEY_F4 0x3D
+#define KEY_F5 0x3E
+#define KEY_F6 0x3F
+#define KEY_F7 0x40
+#define KEY_F8 0x41
+#define KEY_F9 0x42
+#define KEY_F10 0x43
+#define KEY_F11 0x44
+#define KEY_F12 0x45
+#define KEY_PRINTSCREEN 0x46
+#define KEY_SCROLL LOCK 0x47
+#define KEY_PAUSE 0x48
+#define KEY_INSERT 0x49
+#define KEY_HOME 0x4A
+#define KEY_PAGEUP 0x4B
+#define KEY_DELETE 0x4C
+#define KEY_END1 0x4D
+#define KEY_PAGEDOWN 0x4E
+#define KEY_RIGHTARROW 0x4F
+#define KEY_LEFTARROW 0x50
+#define KEY_DOWNARROW 0x51
+#define KEY_UPARROW 0x52
+#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53
+#define KEY_KEYPAD_SLASH 0x54
+#define KEY_KEYPAD_ASTERIKS 0x55
+#define KEY_KEYPAD_MINUS 0x56
+#define KEY_KEYPAD_PLUS 0x57
+#define KEY_KEYPAD_ENTER 0x58
+#define KEY_KEYPAD_1_END 0x59
+#define KEY_KEYPAD_2_DOWN_ARROW 0x5A
+#define KEY_KEYPAD_3_PAGEDN 0x5B
+#define KEY_KEYPAD_4_LEFT_ARROW 0x5C
+#define KEY_KEYPAD_5 0x5D
+#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E
+#define KEY_KEYPAD_7_HOME 0x5F
+#define KEY_KEYPAD_8_UP_ARROW 0x60
+#define KEY_KEYPAD_9_PAGEUP 0x61
+#define KEY_KEYPAD_0_INSERT 0x62
+#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63
+#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64
+#define KEY_APPLICATION 0x65
+#define KEY_POWER 0x66
+#define KEY_KEYPAD_EQUAL 0x67
+#define KEY_F13 0x68
+#define KEY_F14 0x69
+#define KEY_F15 0x6A
+#define KEY_F16 0x6B
+#define KEY_F17 0x6C
+#define KEY_F18 0x6D
+#define KEY_F19 0x6E
+#define KEY_F20 0x6F
+#define KEY_F21 0x70
+#define KEY_F22 0x71
+#define KEY_F23 0x72
+#define KEY_F24 0x73
+#define KEY_EXECUTE 0x74
+#define KEY_HELP 0x75
+#define KEY_MENU 0x76
+#define KEY_SELECT 0x77
+#define KEY_STOP 0x78
+#define KEY_AGAIN 0x79
+#define KEY_UNDO 0x7A
+#define KEY_CUT 0x7B
+#define KEY_COPY 0x7C
+#define KEY_PASTE 0x7D
+#define KEY_FIND 0x7E
+#define KEY_MUTE 0x7F
+#define KEY_VOLUME_UP 0x80
+#define KEY_VOLUME_DOWN 0x81
+#define KEY_LOCKING_CAPS_LOCK 0x82
+#define KEY_LOCKING_NUM_LOCK 0x83
+#define KEY_LOCKING_SCROLL_LOCK 0x84
+#define KEY_KEYPAD_COMMA 0x85
+#define KEY_KEYPAD_EQUAL_SIGN 0x86
+#define KEY_INTERNATIONAL1 0x87
+#define KEY_INTERNATIONAL2 0x88
+#define KEY_INTERNATIONAL3 0x89
+#define KEY_INTERNATIONAL4 0x8A
+#define KEY_INTERNATIONAL5 0x8B
+#define KEY_INTERNATIONAL6 0x8C
+#define KEY_INTERNATIONAL7 0x8D
+#define KEY_INTERNATIONAL8 0x8E
+#define KEY_INTERNATIONAL9 0x8F
+#define KEY_LANG1 0x90
+#define KEY_LANG2 0x91
+#define KEY_LANG3 0x92
+#define KEY_LANG4 0x93
+#define KEY_LANG5 0x94
+#define KEY_LANG6 0x95
+#define KEY_LANG7 0x96
+#define KEY_LANG8 0x97
+#define KEY_LANG9 0x98
+#define KEY_ALTERNATE_ERASE 0x99
+#define KEY_SYSREQ 0x9A
+#define KEY_CANCEL 0x9B
+#define KEY_CLEAR 0x9C
+#define KEY_PRIOR 0x9D
+#define KEY_RETURN 0x9E
+#define KEY_SEPARATOR 0x9F
+#define KEY_OUT 0xA0
+#define KEY_OPER 0xA1
+#define KEY_CLEAR_AGAIN 0xA2
+#define KEY_CRSEL 0xA3
+#define KEY_EXSEL 0xA4
+#define KEY_KEYPAD_00 0xB0
+#define KEY_KEYPAD_000 0xB1
+#define KEY_THOUSANDS_SEPARATOR 0xB2
+#define KEY_DECIMAL_SEPARATOR 0xB3
+#define KEY_CURRENCY_UNIT 0xB4
+#define KEY_CURRENCY_SUB_UNIT 0xB5
+#define KEY_KEYPAD_OPARENTHESIS 0xB6
+#define KEY_KEYPAD_CPARENTHESIS 0xB7
+#define KEY_KEYPAD_OBRACE 0xB8
+#define KEY_KEYPAD_CBRACE 0xB9
+#define KEY_KEYPAD_TAB 0xBA
+#define KEY_KEYPAD_BACKSPACE 0xBB
+#define KEY_KEYPAD_A 0xBC
+#define KEY_KEYPAD_B 0xBD
+#define KEY_KEYPAD_C 0xBE
+#define KEY_KEYPAD_D 0xBF
+#define KEY_KEYPAD_E 0xC0
+#define KEY_KEYPAD_F 0xC1
+#define KEY_KEYPAD_XOR 0xC2
+#define KEY_KEYPAD_CARET 0xC3
+#define KEY_KEYPAD_PERCENT 0xC4
+#define KEY_KEYPAD_LESS 0xC5
+#define KEY_KEYPAD_GREATER 0xC6
+#define KEY_KEYPAD_AMPERSAND 0xC7
+#define KEY_KEYPAD_LOGICAL_AND 0xC8
+#define KEY_KEYPAD_VERTICAL_BAR 0xC9
+#define KEY_KEYPAD_LOGIACL_OR 0xCA
+#define KEY_KEYPAD_COLON 0xCB
+#define KEY_KEYPAD_NUMBER_SIGN 0xCC
+#define KEY_KEYPAD_SPACE 0xCD
+#define KEY_KEYPAD_AT 0xCE
+#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF
+#define KEY_KEYPAD_MEMORY_STORE 0xD0
+#define KEY_KEYPAD_MEMORY_RECALL 0xD1
+#define KEY_KEYPAD_MEMORY_CLEAR 0xD2
+#define KEY_KEYPAD_MEMORY_ADD 0xD3
+#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4
+#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5
+#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6
+#define KEY_KEYPAD_PLUSMINUS 0xD7
+#define KEY_KEYPAD_CLEAR 0xD8
+#define KEY_KEYPAD_CLEAR_ENTRY 0xD9
+#define KEY_KEYPAD_BINARY 0xDA
+#define KEY_KEYPAD_OCTAL 0xDB
+#define KEY_KEYPAD_DECIMAL 0xDC
+#define KEY_KEYPAD_HEXADECIMAL 0xDD
+#define KEY_LEFTCONTROL 0xE0
+#define KEY_LEFTSHIFT 0xE1
+#define KEY_LEFTALT 0xE2
+#define KEY_LEFT_GUI 0xE3
+#define KEY_RIGHTCONTROL 0xE4
+#define KEY_RIGHTSHIFT 0xE5
+#define KEY_RIGHTALT 0xE6
+#define KEY_RIGHT_GUI 0xE7
+
+typedef struct
+{
+ uint8_t state;
+ uint8_t lctrl;
+ uint8_t lshift;
+ uint8_t lalt;
+ uint8_t lgui;
+ uint8_t rctrl;
+ uint8_t rshift;
+ uint8_t ralt;
+ uint8_t rgui;
+ uint8_t keys[6];
+}
+HID_KEYBD_Info_TypeDef;
+
+USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost);
+HID_KEYBD_Info_TypeDef *USBH_HID_GetKeybdInfo(USBH_HandleTypeDef *phost);
+uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_HID_KEYBD_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_mouse.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_mouse.h
new file mode 100644
index 0000000..e8bf542
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_mouse.h
@@ -0,0 +1,125 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_mouse.h
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file contains all the prototypes for the usbh_hid_mouse.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_HID_MOUSE_H
+#define __USBH_HID_MOUSE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_MOUSE
+ * @brief This file is the Header file for usbh_hid_mouse.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Exported_Types
+ * @{
+ */
+
+typedef struct _HID_MOUSE_Info
+{
+ uint8_t x;
+ uint8_t y;
+ uint8_t buttons[3];
+}
+HID_MOUSE_Info_TypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost);
+HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_HID_MOUSE_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_parser.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_parser.h
new file mode 100644
index 0000000..b5dc79f
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_parser.h
@@ -0,0 +1,106 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_parser.c
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file is the header file of the usbh_hid_parser.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive -----------------------------------------------*/
+#ifndef __USBH_HID_PARSER_H
+#define __USBH_HID_PARSER_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+#include "usbh_hid_usage.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_PARSER
+ * @brief This file is the Header file for usbh_hid_parser.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Exported_Types
+ * @{
+ */
+typedef struct
+{
+ uint8_t *data;
+ uint32_t size;
+ uint8_t shift;
+ uint8_t count;
+ uint8_t sign;
+ uint32_t logical_min; /*min value device can return*/
+ uint32_t logical_max; /*max value device can return*/
+ uint32_t physical_min; /*min vale read can report*/
+ uint32_t physical_max; /*max value read can report*/
+ uint32_t resolution;
+}
+HID_Report_ItemTypedef;
+
+
+uint32_t HID_ReadItem (HID_Report_ItemTypedef *ri, uint8_t ndx);
+uint32_t HID_WriteItem(HID_Report_ItemTypedef *ri, uint32_t value, uint8_t ndx);
+
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_HID_PARSER_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_usage.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_usage.h
new file mode 100644
index 0000000..df65995
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Inc/usbh_hid_usage.h
@@ -0,0 +1,200 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_usage.c
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file contain the USAGE page codes
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USDH_HID_USAGE_H
+#define __USDH_HID_USAGE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_USAGE
+ * @brief This file is the Header file for usbh_hid_usage.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_USAGE_Exported_Types
+ * @{
+ */
+
+/****************************************************/
+/* HID 1.11 usage pages */
+/****************************************************/
+
+#define HID_USAGE_PAGE_UNDEFINED uint16_t (0x00) /* Undefined */
+/**** Top level pages */
+#define HID_USAGE_PAGE_GEN_DES uint16_t (0x01) /* Generic Desktop Controls*/
+#define HID_USAGE_PAGE_SIM_CTR uint16_t (0x02) /* Simulation Controls */
+#define HID_USAGE_PAGE_VR_CTR uint16_t (0x03) /* VR Controls */
+#define HID_USAGE_PAGE_SPORT_CTR uint16_t (0x04) /* Sport Controls */
+#define HID_USAGE_PAGE_GAME_CTR uint16_t (0x05) /* Game Controls */
+#define HID_USAGE_PAGE_GEN_DEV uint16_t (0x06) /* Generic Device Controls */
+#define HID_USAGE_PAGE_KEYB uint16_t (0x07) /* Keyboard/Keypad */
+#define HID_USAGE_PAGE_LED uint16_t (0x08) /* LEDs */
+#define HID_USAGE_PAGE_BUTTON uint16_t (0x09) /* Button */
+#define HID_USAGE_PAGE_ORDINAL uint16_t (0x0A) /* Ordinal */
+#define HID_USAGE_PAGE_PHONE uint16_t (0x0B) /* Telephony */
+#define HID_USAGE_PAGE_CONSUMER uint16_t (0x0C) /* Consumer */
+#define HID_USAGE_PAGE_DIGITIZER uint16_t (0x0D) /* Digitizer*/
+/* 0E Reserved */
+#define HID_USAGE_PAGE_PID uint16_t (0x0F) /* PID Page (force feedback and related devices) */
+#define HID_USAGE_PAGE_UNICODE uint16_t (0x10) /* Unicode */
+/* 11-13 Reserved */
+#define HID_USAGE_PAGE_ALNUM_DISP uint16_t (0x14) /* Alphanumeric Display */
+/* 15-1f Reserved */
+/**** END of top level pages */
+/* 25-3f Reserved */
+#define HID_USAGE_PAGE_MEDICAL uint16_t (0x40) /* Medical Instruments */
+/* 41-7F Reserved */
+/*80-83 Monitor pages USB Device Class Definition for Monitor Devices
+ 84-87 Power pages USB Device Class Definition for Power Devices */
+/* 88-8B Reserved */
+#define HID_USAGE_PAGE_BARCODE uint16_t (0x8C) /* Bar Code Scanner page */
+#define HID_USAGE_PAGE_SCALE uint16_t (0x8D) /* Scale page */
+#define HID_USAGE_PAGE_MSR uint16_t (0x8E) /* Magnetic Stripe Reading (MSR) Devices */
+#define HID_USAGE_PAGE_POS uint16_t (0x8F) /* Reserved Point of Sale pages */
+#define HID_USAGE_PAGE_CAMERA_CTR uint16_t (0x90) /* Camera Control Page */
+#define HID_USAGE_PAGE_ARCADE uint16_t (0x91) /* Arcade Page */
+
+/****************************************************/
+/* Usage definitions for the "Generic Desktop" page */
+/****************************************************/
+#define HID_USAGE_UNDEFINED uint16_t (0x00) /* Undefined */
+#define HID_USAGE_POINTER uint16_t (0x01) /* Pointer (Physical Collection) */
+#define HID_USAGE_MOUSE uint16_t (0x02) /* Mouse (Application Collection) */
+/* 03 Reserved */
+#define HID_USAGE_JOYSTICK uint16_t (0x04) /* Joystick (Application Collection) */
+#define HID_USAGE_GAMEPAD uint16_t (0x05) /* Game Pad (Application Collection) */
+#define HID_USAGE_KBD uint16_t (0x06) /* Keyboard (Application Collection) */
+#define HID_USAGE_KEYPAD uint16_t (0x07) /* Keypad (Application Collection) */
+#define HID_USAGE_MAX_CTR uint16_t (0x08) /* Multi-axis Controller (Application Collection) */
+/* 09-2F Reserved */
+#define HID_USAGE_X uint16_t (0x30) /* X (Dynamic Value) */
+#define HID_USAGE_Y uint16_t (0x31) /* Y (Dynamic Value) */
+#define HID_USAGE_Z uint16_t (0x32) /* Z (Dynamic Value) */
+#define HID_USAGE_RX uint16_t (0x33) /* Rx (Dynamic Value) */
+#define HID_USAGE_RY uint16_t (0x34) /* Ry (Dynamic Value) */
+#define HID_USAGE_RZ uint16_t (0x35) /* Rz (Dynamic Value) */
+#define HID_USAGE_SLIDER uint16_t (0x36) /* Slider (Dynamic Value) */
+#define HID_USAGE_DIAL uint16_t (0x37) /* Dial (Dynamic Value) */
+#define HID_USAGE_WHEEL uint16_t (0x38) /* Wheel (Dynamic Value) */
+#define HID_USAGE_HATSW uint16_t (0x39) /* Hat switch (Dynamic Value) */
+#define HID_USAGE_COUNTEDBUF uint16_t (0x3A) /* Counted Buffer (Logical Collection) */
+#define HID_USAGE_BYTECOUNT uint16_t (0x3B) /* Byte Count (Dynamic Value) */
+#define HID_USAGE_MOTIONWAKE uint16_t (0x3C) /* Motion Wakeup (One Shot Control) */
+#define HID_USAGE_START uint16_t (0x3D) /* Start (On/Off Control) */
+#define HID_USAGE_SELECT uint16_t (0x3E) /* Select (On/Off Control) */
+/* 3F Reserved */
+#define HID_USAGE_VX uint16_t (0x40) /* Vx (Dynamic Value) */
+#define HID_USAGE_VY uint16_t (0x41) /* Vy (Dynamic Value) */
+#define HID_USAGE_VZ uint16_t (0x42) /* Vz (Dynamic Value) */
+#define HID_USAGE_VBRX uint16_t (0x43) /* Vbrx (Dynamic Value) */
+#define HID_USAGE_VBRY uint16_t (0x44) /* Vbry (Dynamic Value) */
+#define HID_USAGE_VBRZ uint16_t (0x45) /* Vbrz (Dynamic Value) */
+#define HID_USAGE_VNO uint16_t (0x46) /* Vno (Dynamic Value) */
+#define HID_USAGE_FEATNOTIF uint16_t (0x47) /* Feature Notification (Dynamic Value),(Dynamic Flag) */
+/* 48-7F Reserved */
+#define HID_USAGE_SYSCTL uint16_t (0x80) /* System Control (Application Collection) */
+#define HID_USAGE_PWDOWN uint16_t (0x81) /* System Power Down (One Shot Control) */
+#define HID_USAGE_SLEEP uint16_t (0x82) /* System Sleep (One Shot Control) */
+#define HID_USAGE_WAKEUP uint16_t (0x83) /* System Wake Up (One Shot Control) */
+#define HID_USAGE_CONTEXTM uint16_t (0x84) /* System Context Menu (One Shot Control) */
+#define HID_USAGE_MAINM uint16_t (0x85) /* System Main Menu (One Shot Control) */
+#define HID_USAGE_APPM uint16_t (0x86) /* System App Menu (One Shot Control) */
+#define HID_USAGE_MENUHELP uint16_t (0x87) /* System Menu Help (One Shot Control) */
+#define HID_USAGE_MENUEXIT uint16_t (0x88) /* System Menu Exit (One Shot Control) */
+#define HID_USAGE_MENUSELECT uint16_t (0x89) /* System Menu Select (One Shot Control) */
+#define HID_USAGE_SYSM_RIGHT uint16_t (0x8A) /* System Menu Right (Re-Trigger Control) */
+#define HID_USAGE_SYSM_LEFT uint16_t (0x8B) /* System Menu Left (Re-Trigger Control) */
+#define HID_USAGE_SYSM_UP uint16_t (0x8C) /* System Menu Up (Re-Trigger Control) */
+#define HID_USAGE_SYSM_DOWN uint16_t (0x8D) /* System Menu Down (Re-Trigger Control) */
+#define HID_USAGE_COLDRESET uint16_t (0x8E) /* System Cold Restart (One Shot Control) */
+#define HID_USAGE_WARMRESET uint16_t (0x8F) /* System Warm Restart (One Shot Control) */
+#define HID_USAGE_DUP uint16_t (0x90) /* D-pad Up (On/Off Control) */
+#define HID_USAGE_DDOWN uint16_t (0x91) /* D-pad Down (On/Off Control) */
+#define HID_USAGE_DRIGHT uint16_t (0x92) /* D-pad Right (On/Off Control) */
+#define HID_USAGE_DLEFT uint16_t (0x93) /* D-pad Left (On/Off Control) */
+/* 94-9F Reserved */
+#define HID_USAGE_SYS_DOCK uint16_t (0xA0) /* System Dock (One Shot Control) */
+#define HID_USAGE_SYS_UNDOCK uint16_t (0xA1) /* System Undock (One Shot Control) */
+#define HID_USAGE_SYS_SETUP uint16_t (0xA2) /* System Setup (One Shot Control) */
+#define HID_USAGE_SYS_BREAK uint16_t (0xA3) /* System Break (One Shot Control) */
+#define HID_USAGE_SYS_DBGBRK uint16_t (0xA4) /* System Debugger Break (One Shot Control) */
+#define HID_USAGE_APP_BRK uint16_t (0xA5) /* Application Break (One Shot Control) */
+#define HID_USAGE_APP_DBGBRK uint16_t (0xA6) /* Application Debugger Break (One Shot Control) */
+#define HID_USAGE_SYS_SPKMUTE uint16_t (0xA7) /* System Speaker Mute (One Shot Control) */
+#define HID_USAGE_SYS_HIBERN uint16_t (0xA8) /* System Hibernate (One Shot Control) */
+/* A9-AF Reserved */
+#define HID_USAGE_SYS_SIDPINV uint16_t (0xB0) /* System Display Invert (One Shot Control) */
+#define HID_USAGE_SYS_DISPINT uint16_t (0xB1) /* System Display Internal (One Shot Control) */
+#define HID_USAGE_SYS_DISPEXT uint16_t (0xB2) /* System Display External (One Shot Control) */
+#define HID_USAGE_SYS_DISPBOTH uint16_t (0xB3) /* System Display Both (One Shot Control) */
+#define HID_USAGE_SYS_DISPDUAL uint16_t (0xB4) /* System Display Dual (One Shot Control) */
+#define HID_USAGE_SYS_DISPTGLIE uint16_t (0xB5) /* System Display Toggle Int/Ext (One Shot Control) */
+#define HID_USAGE_SYS_DISP_SWAP uint16_t (0xB6) /* System Display Swap Primary/Secondary (One Shot Control) */
+#define HID_USAGE_SYS_DIPS_LCDA uint16_t (0xB7) /* System Display LCD Autoscale (One Shot Control) */
+/* B8-FFFF Reserved */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USDH_HID_USAGE_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c
new file mode 100644
index 0000000..ed26caa
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c
@@ -0,0 +1,850 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid.c
+ * @author MCD Application Team
+ * @version V3.2.2
+ * @date 07-July-2015
+ * @brief This file is the HID Layer Handlers for USB Host HID class.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * HID Class Description
+ * ===================================================================
+ * This module manages the HID class V1.11 following the "Device Class Definition
+ * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
+ * This driver implements the following aspects of the specification:
+ * - The Boot Interface Subclass
+ * - The Mouse and Keyboard protocols
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+#include "build_config.h"
+
+
+#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_HID_CLASS
+* @{
+*/
+
+/** @defgroup USBH_HID_CORE
+* @brief This file includes HID Layer Handlers for USB Host HID class.
+* @{
+*/
+
+/** @defgroup USBH_HID_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost);
+static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf);
+
+
+USBH_ClassTypeDef HID_Class =
+{
+ "HID",
+ USB_HID_CLASS,
+ USBH_HID_InterfaceInit,
+ USBH_HID_InterfaceDeInit,
+ USBH_HID_ClassRequest,
+ USBH_HID_Process,
+ USBH_HID_SOFProcess,
+ NULL,
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Functions
+* @{
+*/
+
+
+/**
+ * @brief USBH_HID_InterfaceInit
+ * The function init the HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ uint8_t max_ep;
+ uint8_t num = 0;
+ uint8_t interface = 0xFF;
+
+ HID_HandleTypeDef *HID_Handle;
+
+
+#ifdef CONFIG_MOUSE_ENABLED
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, HID_MOUSE_PROTOCOL); //Search for mouse interfaces first
+#endif
+#ifdef CONFIG_KEYBOARD_ENABLED
+ if (interface == 0xFF)
+ {
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, HID_KEYBRD_PROTOCOL);
+ }
+#endif
+
+ if(interface == 0xFF) /* No Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ return USBH_FAIL;
+ }
+
+ USBH_SelectInterface (phost, interface);
+ phost->pActiveClass->pData = (HID_HandleTypeDef *)USBH_malloc (sizeof(HID_HandleTypeDef));
+ HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ HID_Handle->state = HID_INIT;
+ HID_Handle->ctl_state = HID_REQ_INIT;
+ HID_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress;
+ HID_Handle->length = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ HID_Handle->poll = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bInterval;
+ HID_Handle->Protocol = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol;
+
+ if (HID_Handle->poll < HID_MIN_POLL) HID_Handle->poll = HID_MIN_POLL;
+ if (HID_Handle->length > HID_REPORT_BUFFER_SIZE) return USBH_FAIL; //Some mechanical keyboards need to send > 8 byte packets
+
+ /* Check fo available number of endpoints */
+ /* Find the number of EPs in the Interface Descriptor */
+ /* Choose the lower number in order not to overrun the buffer allocated */
+ max_ep = ( (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
+ phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints :
+ USBH_MAX_NUM_ENDPOINTS);
+
+
+ /* Decode endpoint IN and OUT address from interface descriptor */
+ for ( ;num < max_ep; num++)
+ {
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress & 0x80)
+ {
+ HID_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress);
+ HID_Handle->InPipe =\
+ USBH_AllocPipe(phost, HID_Handle->InEp);
+
+ /* Open pipe for IN endpoint */
+ USBH_OpenPipe (phost,
+ HID_Handle->InPipe,
+ HID_Handle->InEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ HID_Handle->length);
+
+ USBH_LL_SetToggle (phost, HID_Handle->InPipe, 0);
+
+ }
+ else
+ {
+ HID_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress);
+ HID_Handle->OutPipe =\
+ USBH_AllocPipe(phost, HID_Handle->OutEp);
+
+ /* Open pipe for OUT endpoint */
+ USBH_OpenPipe (phost,
+ HID_Handle->OutPipe,
+ HID_Handle->OutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ HID_Handle->length);
+
+ USBH_LL_SetToggle (phost, HID_Handle->OutPipe, 0);
+ }
+
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_InterfaceDeInit
+ * The function DeInit the Pipes used for the HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost )
+{
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if(HID_Handle->InPipe != 0x00)
+ {
+ USBH_ClosePipe (phost, HID_Handle->InPipe);
+ USBH_FreePipe (phost, HID_Handle->InPipe);
+ HID_Handle->InPipe = 0; /* Reset the pipe as Free */
+ }
+
+ if(HID_Handle->OutPipe != 0x00)
+ {
+ USBH_ClosePipe(phost, HID_Handle->OutPipe);
+ USBH_FreePipe (phost, HID_Handle->OutPipe);
+ HID_Handle->OutPipe = 0; /* Reset the pipe as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost)
+{
+
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef classReqStatus = USBH_BUSY;
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ /* Switch HID state machine */
+ switch (HID_Handle->ctl_state)
+ {
+ case HID_REQ_INIT:
+ case HID_REQ_GET_HID_DESC:
+
+ /* Get HID Desc */
+ if (USBH_HID_GetHIDDescriptor (phost, USB_HID_DESC_SIZE)== USBH_OK)
+ {
+
+ USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.Data);
+ HID_Handle->ctl_state = HID_REQ_GET_REPORT_DESC;
+ }
+
+ break;
+ case HID_REQ_GET_REPORT_DESC:
+ /* Get Report Desc */
+ if (USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength) == USBH_OK)
+ {
+ /* The descriptor is available in phost->device.Data */
+ HID_Handle->ctl_state = HID_REQ_SET_IDLE;
+ }
+ break;
+
+ case HID_REQ_SET_IDLE:
+ classReqStatus = USBH_HID_SetIdle (phost, 0, 0);
+
+ /* set Idle */
+ if (classReqStatus == USBH_OK)
+ {
+ HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ else if(classReqStatus == USBH_NOT_SUPPORTED)
+ {
+ HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ break;
+
+ case HID_REQ_SET_PROTOCOL:
+ //Mouse in 'report' mode,
+ //Keyboard in 'boot' mode
+ if (USBH_HID_SetProtocol(phost,
+ (HID_Handle->Protocol == HID_MOUSE_PROTOCOL ? 1 : 0)) == USBH_OK)
+ {
+ HID_Handle->ctl_state = HID_REQ_IDLE;
+
+ /* all requests performed*/
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ status = USBH_OK;
+ }
+ break;
+
+ case HID_REQ_IDLE:
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_HID_Process
+ * The function is for managing state machine for HID data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
+{
+ USBH_URBStateTypeDef urbStatus;
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (HID_Handle->state)
+ {
+ case HID_INIT:
+ HID_Handle->timer = phost->Timer;
+ HID_Handle->state = HID_IDLE;
+ break;
+
+ case HID_IDLE:
+ break;
+
+ case HID_GET_DATA:
+ if ((int32_t)(phost->Timer - HID_Handle->timer) >= HID_Handle->poll)
+ {
+ USBH_InterruptReceiveData(phost,
+ HID_Handle->Data,
+ HID_Handle->length,
+ HID_Handle->InPipe);
+ HID_Handle->state = HID_GET_POLL;
+ HID_Handle->timer = phost->Timer;
+ }
+ break;
+
+ case HID_GET_POLL:
+ urbStatus = USBH_LL_GetURBState(phost, HID_Handle->InPipe);
+
+ if (urbStatus == USBH_URB_DONE)
+ {
+ HID_Handle->ReportCallback(USBH_OK);
+ HID_Handle->state = HID_IDLE;
+ break;
+ }
+
+ if (urbStatus == USBH_URB_NOTREADY)
+ {
+ HID_Handle->ReportCallback(USBH_BUSY);
+ HID_Handle->state = HID_IDLE;
+ break;
+ }
+
+ if (urbStatus == USBH_URB_STALL)
+ {
+ /* Issue Clear Feature on interrupt IN endpoint */
+ if(USBH_ClrFeature(phost,
+ HID_Handle->ep_addr) == USBH_OK)
+ {
+ HID_Handle->ReportCallback(USBH_BUSY);
+ HID_Handle->state = HID_IDLE;
+ }
+ }
+ break;
+
+ case HID_SET_DATA_POLL:
+ if (USBH_CtlReq(phost, HID_Handle->Data, phost->Control.setup.b.wLength.w) == USBH_OK)
+ {
+ HID_Handle->ReportCallback(USBH_OK);
+ HID_Handle->state = HID_IDLE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_SOFProcess
+ * The function is for managing the SOF Process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+
+
+//Downstream_HID calls into here at main() priority,
+//to request a new report for Upstream.
+HAL_StatusTypeDef USBH_HID_GetInterruptReport(USBH_HandleTypeDef *phost,
+ TransactionCompleteCallbackTypeDef callback)
+{
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if (HID_Handle->state == HID_IDLE)
+ {
+ HID_Handle->ReportCallback = callback;
+ HID_Handle->state = HID_GET_DATA;
+ return HAL_OK;
+ }
+
+ //return HAL_ERROR;
+ while (1);
+}
+
+
+
+
+/**
+* @brief USBH_Get_HID_ReportDescriptor
+ * Issue report Descriptor command to the device. Once the response
+ * received, parse the report descriptor and update the status.
+ * @param phost: Host handle
+ * @param Length : HID Report Descriptor Length
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length)
+{
+
+ USBH_StatusTypeDef status;
+
+ if (length > USBH_MAX_DATA_BUFFER)
+ {
+ length = USBH_MAX_DATA_BUFFER;
+ }
+
+ status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID_REPORT,
+ phost->device.current_interface,
+ phost->device.Data,
+ length);
+
+ /* HID report descriptor is available in phost->device.Data.
+ In case of USB Boot Mode devices for In report handling ,
+ HID report descriptor parsing is not required.
+ In case, for supporting Non-Boot Protocol devices and output reports,
+ user may parse the report descriptor*/
+
+
+ return status;
+}
+
+/**
+ * @brief USBH_Get_HID_Descriptor
+ * Issue HID Descriptor command to the device. Once the response
+ * received, parse the report descriptor and update the status.
+ * @param phost: Host handle
+ * @param Length : HID Descriptor Length
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length)
+{
+
+ USBH_StatusTypeDef status;
+
+ if (length > USBH_MAX_DATA_BUFFER)
+ {
+ length = USBH_MAX_DATA_BUFFER;
+ }
+
+ status = USBH_GetDescriptor( phost,
+ USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID,
+ phost->device.current_interface,
+ phost->device.Data,
+ length);
+
+ return status;
+}
+
+/**
+ * @brief USBH_Set_Idle
+ * Set Idle State.
+ * @param phost: Host handle
+ * @param duration: Duration for HID Idle request
+ * @param reportId : Targeted report ID for Set Idle request
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost,
+ uint8_t duration,
+ uint8_t reportId)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_RECIPIENT_INTERFACE |
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_IDLE;
+ phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+
+/**
+ * @brief USBH_HID_Set_Report
+ * Issues Set Report
+ * @param phost: Host handle
+ * @param reportType : Report type to be sent
+ * @param reportId : Targeted report ID for Set Report request
+ * @param reportBuff : Report Buffer
+ * @param reportLen : Length of data report to be send
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen,
+ TransactionCompleteCallbackTypeDef callback)
+{
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+ uint32_t i;
+
+ if (phost->RequestState == CMD_SEND)
+ {
+ if ((HID_Handle->state != HID_IDLE) ||
+ (reportLen > HID_MAX_REPORT_SIZE))
+ {
+ while (1);
+ }
+
+ HID_Handle->ReportCallback = callback;
+ HID_Handle->state = HID_SET_DATA_POLL;
+ for (i = 0; i < reportLen; i++)
+ {
+ HID_Handle->Data[i] = *reportBuff;
+ reportBuff++;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_RECIPIENT_INTERFACE |
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_REPORT;
+ phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = reportLen;
+ }
+
+ //return USBH_CtlReq(phost, reportBuff, reportLen);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_HID_GetReport
+ * retreive Set Report
+ * @param phost: Host handle
+ * @param reportType : Report type to be sent
+ * @param reportId : Targeted report ID for Set Report request
+ * @param reportBuff : Report Buffer
+ * @param reportLen : Length of data report to be send
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_D2H |
+ USB_REQ_RECIPIENT_INTERFACE |
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = USB_HID_GET_REPORT;
+ phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = reportLen;
+ }
+
+ return USBH_CtlReq(phost, reportBuff , reportLen );
+}
+
+/**
+ * @brief USBH_Set_Protocol
+ * Set protocol State.
+ * @param phost: Host handle
+ * @param protocol : Set Protocol for HID : boot/report protocol
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetProtocol(USBH_HandleTypeDef *phost,
+ uint8_t protocol)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_RECIPIENT_INTERFACE |\
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL;
+ phost->Control.setup.b.wValue.w = protocol == 0 ? 0 : 1;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+
+ return USBH_CtlReq(phost, 0 , 0 );
+
+}
+
+/**
+ * @brief USBH_ParseHIDDesc
+ * This function Parse the HID descriptor
+ * @param desc: HID Descriptor
+ * @param buf: Buffer where the source descriptor is available
+ * @retval None
+ */
+static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf)
+{
+
+ desc->bLength = *(uint8_t *) (buf + 0);
+ desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ desc->bcdHID = LE16 (buf + 2);
+ desc->bCountryCode = *(uint8_t *) (buf + 4);
+ desc->bNumDescriptors = *(uint8_t *) (buf + 5);
+ desc->bReportDescriptorType = *(uint8_t *) (buf + 6);
+ desc->wItemLength = LE16 (buf + 7);
+}
+
+/**
+ * @brief USBH_HID_GetDeviceType
+ * Return Device function.
+ * @param phost: Host handle
+ * @retval HID function: HID_MOUSE / HID_KEYBOARD
+ */
+HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost)
+{
+ HID_TypeTypeDef type = HID_UNKNOWN;
+
+ if(phost->gState == HOST_CLASS)
+ {
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \
+ == HID_KEYBRD_PROTOCOL)
+ {
+ type = HID_KEYBOARD;
+ }
+ else if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \
+ == HID_MOUSE_PROTOCOL)
+ {
+ type= HID_MOUSE;
+ }
+ }
+ return type;
+}
+
+
+/**
+ * @brief USBH_HID_GetPollInterval
+ * Return HID device poll time
+ * @param phost: Host handle
+ * @retval poll time (ms)
+ */
+uint8_t USBH_HID_GetPollInterval(USBH_HandleTypeDef *phost)
+{
+ HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if((phost->gState == HOST_CLASS_REQUEST) ||
+ (phost->gState == HOST_INPUT) ||
+ (phost->gState == HOST_SET_CONFIGURATION) ||
+ (phost->gState == HOST_CHECK_CLASS) ||
+ ((phost->gState == HOST_CLASS)))
+ {
+ return (HID_Handle->poll);
+ }
+ else
+ {
+ return 0;
+ }
+}
+/**
+ * @brief fifo_init
+ * Initialize FIFO.
+ * @param f: Fifo address
+ * @param buf: Fifo buffer
+ * @param size: Fifo Size
+ * @retval none
+ */
+void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size)
+{
+ f->head = 0;
+ f->tail = 0;
+ f->lock = 0;
+ f->size = size;
+ f->buf = buf;
+}
+
+/**
+ * @brief fifo_read
+ * Read from FIFO.
+ * @param f: Fifo address
+ * @param buf: read buffer
+ * @param nbytes: number of item to read
+ * @retval number of read items
+ */
+uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes)
+{
+ uint16_t i;
+ uint8_t * p;
+ p = (uint8_t*) buf;
+
+ if(f->lock == 0)
+ {
+ f->lock = 1;
+ for(i=0; i < nbytes; i++)
+ {
+ if( f->tail != f->head )
+ {
+ *p++ = f->buf[f->tail];
+ f->tail++;
+ if( f->tail == f->size )
+ {
+ f->tail = 0;
+ }
+ } else
+ {
+ f->lock = 0;
+ return i;
+ }
+ }
+ }
+ f->lock = 0;
+ return nbytes;
+}
+
+/**
+ * @brief fifo_write
+ * Read from FIFO.
+ * @param f: Fifo address
+ * @param buf: read buffer
+ * @param nbytes: number of item to write
+ * @retval number of written items
+ */
+uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes)
+{
+ uint16_t i;
+ const uint8_t * p;
+ p = (const uint8_t*) buf;
+ if(f->lock == 0)
+ {
+ f->lock = 1;
+ for(i=0; i < nbytes; i++)
+ {
+ if( (f->head + 1 == f->tail) ||
+ ( (f->head + 1 == f->size) && (f->tail == 0)) )
+ {
+ f->lock = 0;
+ return i;
+ }
+ else
+ {
+ f->buf[f->head] = *p++;
+ f->head++;
+ if( f->head == f->size )
+ {
+ f->head = 0;
+ }
+ }
+ }
+ }
+ f->lock = 0;
+ return nbytes;
+}
+
+
+/**
+* @brief The function is a callback about HID Data events
+* @param phost: Selected device
+* @retval None
+*/
+__weak void USBH_HID_EventCallback(USBH_HandleTypeDef *phost)
+{
+
+}
+
+#endif //#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h
new file mode 100644
index 0000000..b49884b
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h
@@ -0,0 +1,241 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file contains all the prototypes for the usbh_msc.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_H
+#define __USBH_MSC_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "usbh_msc_bot.h"
+#include "usbh_msc_scsi.h"
+
+
+
+
+typedef enum
+{
+ MSC_INIT = 0,
+ MSC_IDLE,
+ MSC_TEST_UNIT_READY,
+ MSC_READ_CAPACITY10,
+ MSC_READ_INQUIRY,
+ MSC_REQUEST_SENSE,
+ MSC_REQUEST_SENSE_WAIT_RETRY,
+ MSC_READ,
+ MSC_WRITE,
+ MSC_UNRECOVERED_ERROR,
+ MSC_START_STOP,
+}
+MSC_StateTypeDef;
+
+typedef enum
+{
+ MSC_OK,
+ MSC_NOT_READY,
+ MSC_ERROR,
+
+}
+MSC_ErrorTypeDef;
+
+typedef enum
+{
+ MSC_REQ_IDLE = 0,
+ MSC_REQ_STARTUP_DELAY,
+ MSC_REQ_GET_MAX_LUN,
+ MSC_REQ_RESET,
+ MSC_REQ_ERROR,
+}
+MSC_ReqStateTypeDef;
+
+#ifndef MAX_SUPPORTED_LUN
+ #define MAX_SUPPORTED_LUN 2
+#endif
+
+
+/* Structure for LUN */
+typedef struct
+{
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ USBH_StatusTypeDef prev_ready_state;
+ SCSI_CapacityTypeDef capacity;
+ SCSI_SenseTypeDef sense;
+ SCSI_StdInquiryDataTypeDef inquiry;
+ uint8_t state_changed;
+
+}
+MSC_LUNTypeDef;
+
+
+typedef void (*MSC_CmdCompleteCallback)(USBH_StatusTypeDef result);
+
+/* Structure for MSC process */
+typedef struct _MSC_Process
+{
+ uint32_t max_lun;
+ uint8_t InPipe;
+ uint8_t OutPipe;
+ uint8_t OutEp;
+ uint8_t InEp;
+ uint16_t OutEpSize;
+ uint16_t InEpSize;
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ MSC_ReqStateTypeDef req_state;
+ MSC_ReqStateTypeDef prev_req_state;
+ BOT_HandleTypeDef hbot;
+ MSC_LUNTypeDef unit[MAX_SUPPORTED_LUN];
+ uint16_t current_lun;
+ uint16_t rw_lun;
+ uint32_t timeout;
+ uint32_t retry_timeout;
+ MSC_CmdCompleteCallback CmdCompleteCallback;
+}
+MSC_HandleTypeDef;
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Defines
+ * @{
+ */
+
+#define USB_REQ_BOT_RESET 0xFF
+#define USB_REQ_GET_MAX_LUN 0xFE
+
+#define MSC_TIMEOUT_FIXED_MS 10000 //Some flash drives take 2 seconds to write a single block!
+#define MSC_SAMSUNG_STARTUP_DELAY_MS 100 //Samsung FIT Plus 32GB USB 3.1 flash drive was here
+
+/* MSC Class Codes */
+#define USB_MSC_CLASS 0x08
+
+/* Interface Descriptor field values for MSC Protocol */
+#define MSC_BOT 0x50
+#define MSC_TRANSPARENT 0x06
+
+#define MSC_STARTUP_TIMEOUT_MS 15000
+#define MSC_STARTUP_RETRY_TIME_MS 100
+
+#define MSC_START_STOP_EJECT_FLAG 0
+#define MSC_START_STOP_LOAD_FLAG 1
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef USBH_msc;
+#define USBH_MSC_CLASS &USBH_msc
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+/* Common APIs */
+uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost);
+
+/* APIs for LUN */
+int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost);
+
+uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ MSC_CmdCompleteCallback callback);
+
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info);
+
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length,
+ MSC_CmdCompleteCallback callback);
+
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length,
+ MSC_CmdCompleteCallback callback);
+
+USBH_StatusTypeDef USBH_MSC_StartStopUnit(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint8_t startStop,
+ MSC_CmdCompleteCallback callback);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h
new file mode 100644
index 0000000..0a57b5b
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h
@@ -0,0 +1,249 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_msc_bot.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_BOT_H
+#define __USBH_MSC_BOT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "downstream_spi.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_BOT
+ * @brief This file is the Header file for usbh_msc_bot.c
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Types
+ * @{
+ */
+
+typedef enum {
+ BOT_OK = 0,
+ BOT_FAIL = 1,
+ BOT_PHASE_ERROR = 2,
+ BOT_BUSY = 3
+}
+BOT_StatusTypeDef;
+
+typedef enum {
+ BOT_CMD_IDLE = 0,
+ BOT_CMD_SEND,
+ BOT_CMD_WAIT,
+}
+BOT_CMDStateTypeDef;
+
+/* CSW Status Definitions */
+typedef enum
+{
+
+ BOT_CSW_CMD_PASSED = 0x00,
+ BOT_CSW_CMD_FAILED = 0x01,
+ BOT_CSW_PHASE_ERROR = 0x02,
+}
+BOT_CSWStatusTypeDef;
+
+typedef enum {
+ BOT_SEND_CBW = 1,
+ BOT_SEND_CBW_WAIT,
+ BOT_DATA_IN,
+ BOT_DATA_IN_WAIT_FREE_PACKET,
+ BOT_DATA_IN_WAIT,
+ BOT_DATA_OUT,
+ BOT_DATA_OUT_WAIT_RECEIVE_PACKET,
+ BOT_DATA_OUT_WAIT,
+ BOT_RECEIVE_CSW,
+ BOT_RECEIVE_CSW_WAIT,
+ BOT_ERROR_IN,
+ BOT_ERROR_OUT,
+ BOT_UNRECOVERED_ERROR
+}
+BOT_StateTypeDef;
+
+typedef union
+{
+ struct __CBW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataTransferLength;
+ uint8_t Flags;
+ uint8_t LUN;
+ uint8_t CBLength;
+ uint8_t CB[16];
+ }field;
+ uint8_t data[31];
+}
+BOT_CBWTypeDef;
+
+typedef union
+{
+ struct __CSW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataResidue;
+ uint8_t Status;
+ }field;
+ uint8_t data[13];
+}
+BOT_CSWTypeDef;
+
+typedef struct
+{
+ uint32_t data[16];
+ BOT_StateTypeDef state;
+ BOT_StateTypeDef prev_state;
+ BOT_CMDStateTypeDef cmd_state;
+ BOT_CBWTypeDef cbw;
+ uint8_t Reserved1;
+ BOT_CSWTypeDef csw;
+ uint8_t Reserved2[3];
+ uint8_t* pbuf;
+ DownstreamPacketTypeDef* bot_packet;
+ uint8_t* bot_packet_pbuf;
+ uint16_t bot_packet_bytes_remaining;
+ uint16_t this_URB_size;
+}
+BOT_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Defines
+ * @{
+ */
+#define BOT_CBW_SIGNATURE 0x43425355
+#define BOT_CBW_TAG 0x20304050
+#define BOT_CSW_SIGNATURE 0x53425355
+#define BOT_CBW_LENGTH 31
+#define BOT_CSW_LENGTH 13
+
+
+
+#define BOT_SEND_CSW_DISABLE 0
+#define BOT_SEND_CSW_ENABLE 1
+
+#define BOT_DIR_IN 0
+#define BOT_DIR_OUT 1
+#define BOT_DIR_BOTH 2
+
+
+#define BOT_CBW_CB_LENGTH 16
+
+
+#define USB_REQ_BOT_RESET 0xFF
+#define USB_REQ_GET_MAX_LUN 0xFE
+
+#define MAX_BULK_STALL_COUNT_LIMIT 0x04 /* If STALL is seen on Bulk
+ Endpoint continuously, this means
+ that device and Host has phase error
+ Hence a Reset is needed */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun);
+
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun);
+USBH_StatusTypeDef USBH_MSC_BOT_Error(USBH_HandleTypeDef *phost, uint8_t lun);
+
+
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_BOT_H__ */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h
new file mode 100644
index 0000000..c1a20e7
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h
@@ -0,0 +1,232 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_msc_scsi.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_SCSI_H
+#define __USBH_MSC_SCSI_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file is the Header file for usbh_msc_scsi.c
+ * @{
+ */
+
+
+// Capacity data.
+typedef struct
+{
+ uint32_t block_nbr;
+ uint16_t block_size;
+} SCSI_CapacityTypeDef;
+
+
+// Sense data.
+typedef struct
+{
+ uint8_t key;
+ uint8_t asc;
+ uint8_t ascq;
+} SCSI_SenseTypeDef;
+
+// INQUIRY data.
+typedef struct
+{
+ uint8_t PeripheralQualifier;
+ uint8_t DeviceType;
+ uint8_t RemovableMedia;
+ uint8_t vendor_id[9];
+ uint8_t product_id[17];
+ uint8_t revision_id[5];
+}SCSI_StdInquiryDataTypeDef;
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define OPCODE_TEST_UNIT_READY 0x00
+#define OPCODE_READ_CAPACITY10 0x25
+#define OPCODE_READ10 0x28
+#define OPCODE_WRITE10 0x2A
+#define OPCODE_REQUEST_SENSE 0x03
+#define OPCODE_INQUIRY 0x12
+#define OPCODE_START_STOP_UNIT 0x1B
+
+#define DATA_LEN_MODE_TEST_UNIT_READY 0
+#define DATA_LEN_READ_CAPACITY10 8
+#define DATA_LEN_INQUIRY 36
+#define DATA_LEN_REQUEST_SENSE 14
+#define DATA_LEN_START_STOP_UNIT 0
+
+#define CBW_CB_LENGTH 16
+#define CBW_LENGTH 10
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_SENSE_KEY_NO_SENSE 0x00
+#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
+#define SCSI_SENSE_KEY_NOT_READY 0x02
+#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
+#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
+#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
+#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
+#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
+#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
+#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
+#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
+#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
+#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
+#define SCSI_ASC_LOGICAL_UNIT_NOT_READY 0x04
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_WRITE_PROTECTED 0x27
+#define SCSI_ASC_FORMAT_ERROR 0x31
+#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20
+#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
+#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
+#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup _Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
+ uint8_t lun);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_StartStopUnit (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint8_t startStop);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_SCSI_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c
new file mode 100644
index 0000000..876a10b
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c
@@ -0,0 +1,892 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements the MSC class driver functions
+ * ===================================================================
+ * MSC Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.0 following the "Universal
+ * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+ * Sep. 31, 1999".
+ * This driver implements the following aspects of the specification:
+ * - Bulk-Only Transport protocol
+ * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "usbh_msc.h"
+#include "usbh_msc_bot.h"
+#include "usbh_msc_scsi.h"
+#include "interrupts.h"
+#include "build_config.h"
+
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_CORE
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
+ * @{
+ */
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun);
+
+USBH_ClassTypeDef USBH_msc =
+{
+ "MSC",
+ USB_MSC_CLASS,
+ USBH_MSC_InterfaceInit,
+ USBH_MSC_InterfaceDeInit,
+ USBH_MSC_ClassRequest,
+ USBH_MSC_Process,
+ USBH_MSC_SOFProcess,
+ NULL,
+};
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_InterfaceInit
+ * The function init the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ uint8_t interface = 0;
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle;
+
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, 0xFF, MSC_BOT);//MSC_TRANSPARENT, MSC_BOT); //Ignore subclass?!!
+
+ if(interface == 0xFF) /* Not Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ status = USBH_FAIL;
+ }
+ else
+ {
+ USBH_SelectInterface (phost, interface);
+
+ phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc (sizeof(MSC_HandleTypeDef));
+ MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ }
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
+ }
+
+ MSC_Handle->current_lun = 0;
+ MSC_Handle->rw_lun = 0;
+ MSC_Handle->state = MSC_INIT;
+ MSC_Handle->error = MSC_OK;
+ MSC_Handle->req_state = MSC_REQ_IDLE;
+ MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp);
+ MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp);
+ MSC_Handle->CmdCompleteCallback = NULL;
+
+ USBH_MSC_BOT_Init(phost);
+
+ /* De-Initialize LUNs information */
+ USBH_memset(MSC_Handle->unit, 0, sizeof(MSC_Handle->unit));
+
+ /* Open the new channels */
+ USBH_OpenPipe (phost,
+ MSC_Handle->OutPipe,
+ MSC_Handle->OutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MSC_Handle->OutEpSize);
+
+ USBH_OpenPipe (phost,
+ MSC_Handle->InPipe,
+ MSC_Handle->InEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MSC_Handle->InEpSize);
+
+
+ USBH_LL_SetToggle (phost, MSC_Handle->InPipe,0);
+ USBH_LL_SetToggle (phost, MSC_Handle->OutPipe,0);
+ status = USBH_OK;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_InterfaceDeInit
+ * The function DeInit the Pipes used for the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ( MSC_Handle->OutPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->OutPipe);
+ USBH_FreePipe (phost, MSC_Handle->OutPipe);
+ MSC_Handle->OutPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if ( MSC_Handle->InPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->InPipe);
+ USBH_FreePipe (phost, MSC_Handle->InPipe);
+ MSC_Handle->InPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef status = USBH_BUSY;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->req_state)
+ {
+ case MSC_REQ_IDLE:
+ MSC_Handle->timeout = HAL_GetTick();
+ MSC_Handle->req_state = MSC_REQ_STARTUP_DELAY;
+ break;
+
+ case MSC_REQ_STARTUP_DELAY:
+ if ((HAL_GetTick() - MSC_Handle->timeout) > MSC_SAMSUNG_STARTUP_DELAY_MS)
+ {
+ MSC_Handle->req_state = MSC_REQ_GET_MAX_LUN;
+ }
+ break;
+
+ case MSC_REQ_GET_MAX_LUN:
+ /* Issue GetMaxLUN request */
+ status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun);
+
+ /* When devices do not support the GetMaxLun request, this should
+ be considred as only one logical unit is supported */
+ if(status == USBH_NOT_SUPPORTED)
+ {
+ MSC_Handle->max_lun = 0;
+ status = USBH_OK;
+ }
+
+ if(status == USBH_OK)
+ {
+ MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1;
+ USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun));
+
+ if (MSC_Handle->max_lun > MAX_SUPPORTED_LUN)
+ {
+ MSC_Handle->max_lun = MAX_SUPPORTED_LUN;
+ }
+ MSC_Handle->req_state = MSC_REQ_IDLE;
+ }
+ break;
+
+ case MSC_REQ_ERROR :
+ /* a Clear Feature should be issued here */
+ if(USBH_ClrFeature(phost, 0x00) == USBH_OK)
+ {
+ MSC_Handle->req_state = MSC_Handle->prev_req_state;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_Process
+ * The function is for managing state machine for MSC data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY ;
+ USBH_StatusTypeDef ready_status = USBH_BUSY ;
+
+
+ switch (MSC_Handle->state)
+ {
+ case MSC_INIT:
+
+ if(MSC_Handle->current_lun < MSC_Handle->max_lun)
+ {
+
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[MSC_Handle->current_lun].state)
+ {
+ case MSC_INIT:
+ USBH_UsrLog ("LUN #%d: ", MSC_Handle->current_lun);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY;
+ MSC_Handle->timeout = HAL_GetTick();
+ //Fallthrough
+
+ case MSC_READ_INQUIRY:
+ scsi_status = USBH_MSC_SCSI_Inquiry(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry);
+
+ if( scsi_status == USBH_OK)
+ {
+ USBH_UsrLog ("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id);
+ USBH_UsrLog ("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id);
+ USBH_UsrLog ("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_TEST_UNIT_READY:
+ ready_status = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->current_lun);
+
+ if( ready_status == USBH_OK)
+ {
+ if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
+ USBH_UsrLog ("MSC Device ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK;
+ }
+ if( ready_status == USBH_FAIL)
+ {
+ /* Media not ready, so try to check again during 10s */
+ if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
+ USBH_UsrLog ("MSC Device NOT ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL;
+ }
+ else if(ready_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_READ_CAPACITY10:
+ scsi_status = USBH_MSC_SCSI_ReadCapacity(phost,MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ if(MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1)
+ {
+ USBH_UsrLog ("MSC Device capacity : %lu Bytes", \
+ (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
+ USBH_UsrLog ("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr));
+ USBH_UsrLog ("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->current_lun++;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense);
+
+ if( scsi_status == USBH_OK)
+ {
+ if((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) ||
+ (MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY) )
+ {
+ if((HAL_GetTick() - MSC_Handle->timeout) < MSC_STARTUP_TIMEOUT_MS)
+ {
+ MSC_Handle->retry_timeout = HAL_GetTick();
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE_WAIT_RETRY;
+ break;
+ }
+ }
+
+ USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key);
+ USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc);
+ USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->current_lun++;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog ("MSC Device NOT ready");
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_REQUEST_SENSE_WAIT_RETRY:
+ if ((HAL_GetTick() - MSC_Handle->retry_timeout) > MSC_STARTUP_RETRY_TIME_MS)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ }
+ break;
+
+ case MSC_UNRECOVERED_ERROR:
+ MSC_Handle->current_lun++;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ MSC_Handle->current_lun = 0;
+ MSC_Handle->state = MSC_IDLE;
+
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ }
+ break;
+
+ case MSC_IDLE:
+ error = USBH_OK;
+ break;
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ case MSC_WRITE:
+#endif
+ case MSC_READ:
+ error = USBH_MSC_RdWrProcess(phost, MSC_Handle->rw_lun);
+ if(((int32_t)(HAL_GetTick() - MSC_Handle->timeout) > 0) || (phost->device.is_connected == 0))
+ {
+ error = USBH_FAIL;
+ }
+
+ if (error != USBH_BUSY)
+ {
+ MSC_Handle->state = MSC_IDLE;
+ if (MSC_Handle->CmdCompleteCallback != NULL)
+ {
+ MSC_Handle->CmdCompleteCallback(error);
+ MSC_Handle->CmdCompleteCallback = NULL;
+ }
+ }
+ break;
+
+ case MSC_TEST_UNIT_READY:
+ error = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->rw_lun);
+
+ if (((int32_t)(HAL_GetTick() - MSC_Handle->timeout) > 0) || (phost->device.is_connected == 0))
+ {
+ error = USBH_FAIL;
+ }
+ if (error != USBH_BUSY)
+ {
+ MSC_Handle->state = MSC_IDLE;
+ if (error == USBH_OK)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ }
+ if (MSC_Handle->CmdCompleteCallback != NULL)
+ {
+ MSC_Handle->CmdCompleteCallback(error);
+ MSC_Handle->CmdCompleteCallback = NULL;
+ }
+ }
+ break;
+
+ case MSC_START_STOP:
+ error = USBH_MSC_SCSI_StartStopUnit(phost, MSC_Handle->rw_lun, 0);
+
+ if((error != USBH_BUSY) ||
+ ((int32_t)(HAL_GetTick() - MSC_Handle->timeout) > 0) || (phost->device.is_connected == 0))
+ {
+ MSC_Handle->state = MSC_IDLE;
+ error = USBH_OK;
+
+ if (MSC_Handle->CmdCompleteCallback != NULL)
+ {
+ MSC_Handle->CmdCompleteCallback(USBH_OK);
+ MSC_Handle->CmdCompleteCallback = NULL;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return error;
+}
+
+
+/**
+ * @brief USBH_MSC_SOFProcess
+ * The function is for SOF state
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+/**
+ * @brief USBH_MSC_RdWrProcess
+ * The function is for managing state machine for MSC I/O Process
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY ;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[lun].state)
+ {
+
+ case MSC_READ:
+ scsi_status = USBH_MSC_SCSI_Read(phost,lun, 0, 0) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ case MSC_WRITE:
+ scsi_status = USBH_MSC_SCSI_Write(phost,lun, 0, 0) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense);
+
+ if( scsi_status == USBH_OK)
+ {
+ USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[lun].sense.key);
+ USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc);
+ USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq);
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ MSC_Handle->unit[lun].error = MSC_ERROR;
+ error = USBH_FAIL;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog ("MSC Device NOT ready");
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+
+ default:
+ break;
+
+ }
+ return error;
+}
+
+
+/**
+ * @brief USBH_MSC_GetMaxLUN
+ * The function return the Max LUN supported
+ * @param phost: Host handle
+ * @retval logical Unit Number supported
+ */
+int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE))
+ {
+ return MSC_Handle->max_lun;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_MSC_UnitIsReady
+ * The function check whether a LUN is ready
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval Lun status (0: not ready / 1: ready)
+ */
+uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ MSC_CmdCompleteCallback callback)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_TEST_UNIT_READY;
+ MSC_Handle->rw_lun = lun;
+ MSC_Handle->CmdCompleteCallback = callback;
+ MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS;
+
+ return USBH_MSC_SCSI_TestUnitReady(phost, lun);
+}
+
+/**
+ * @brief USBH_MSC_GetLUNInfo
+ * The function return a LUN information
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ if(phost->gState == HOST_CLASS)
+ {
+ USBH_memcpy(info,&MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef));
+ return USBH_OK;
+ }
+ else
+ {
+ return USBH_FAIL;
+ }
+}
+
+/**
+ * @brief USBH_MSC_Read
+ * The function performs a Read operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length,
+ MSC_CmdCompleteCallback callback)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->state != MSC_IDLE) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_READ;
+ MSC_Handle->unit[lun].state = MSC_READ;
+ MSC_Handle->rw_lun = lun;
+ MSC_Handle->CmdCompleteCallback = callback;
+ MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS;
+
+ return USBH_MSC_SCSI_Read(phost,
+ lun,
+ address,
+ length);
+}
+
+
+
+/**
+ * @brief USBH_MSC_Write
+ * The function performs a Write operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length,
+ MSC_CmdCompleteCallback callback)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->state != MSC_IDLE) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_WRITE;
+ MSC_Handle->unit[lun].state = MSC_WRITE;
+ MSC_Handle->rw_lun = lun;
+ MSC_Handle->CmdCompleteCallback = callback;
+ MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS;
+
+ return USBH_MSC_SCSI_Write(phost,
+ lun,
+ address,
+ length);
+}
+#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+
+
+
+USBH_StatusTypeDef USBH_MSC_StartStopUnit(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint8_t startStop,
+ MSC_CmdCompleteCallback callback)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_START_STOP;
+ MSC_Handle->rw_lun = lun;
+ MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS;
+ MSC_Handle->CmdCompleteCallback = callback;
+
+ return USBH_MSC_SCSI_StartStopUnit(phost,
+ lun,
+ startStop);
+}
+
+
+#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c
new file mode 100644
index 0000000..dd48182
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c
@@ -0,0 +1,737 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file includes the BOT protocol related functions
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_msc_bot.h"
+#include "usbh_msc.h"
+#include "downstream_spi.h"
+#include "downstream_msc.h"
+#include "downstream_statemachine.h"
+#include "build_config.h"
+
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir);
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost);
+void USBH_MSC_BOT_Read_Multipacket_FreePacketCallback(DownstreamPacketTypeDef* freePacket);
+void USBH_MSC_BOT_Read_Multipacket_PrepareURB(USBH_HandleTypeDef *phost);
+void USBH_MSC_BOT_Write_Multipacket_ReceivePacketCallback(DownstreamPacketTypeDef* receivedPacket,
+ uint16_t dataLength);
+void USBH_MSC_BOT_Write_Multipacket_PrepareURB(USBH_HandleTypeDef *phost);
+
+
+
+USBH_HandleTypeDef *Callback_MSC_phost;
+
+
+/**
+ * @brief USBH_MSC_BOT_REQ_Reset
+ * The function the MSC BOT Reset request.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_TYPE_CLASS |
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
+ phost->Control.setup.b.wValue.w = 0;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_MSC_BOT_REQ_GetMaxLUN
+ * The function the MSC BOT GetMaxLUN request.
+ * @param phost: Host handle
+ * @param Maxlun: pointer to Maxlun variable
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_D2H |
+ USB_REQ_TYPE_CLASS |
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
+ phost->Control.setup.b.wValue.w = 0;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 1;
+ }
+
+ return USBH_CtlReq(phost, Maxlun , 1 );
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Init
+ * The function Initializes the BOT protocol.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost)
+{
+
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ MSC_Handle->hbot.cbw.field.Signature = BOT_CBW_SIGNATURE;
+ MSC_Handle->hbot.cbw.field.Tag = BOT_CBW_TAG;
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+
+ return USBH_OK;
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Process
+ * The function handle the BOT protocol.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef error = USBH_BUSY;
+ BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ uint32_t partialTransferLength;
+ uint8_t toggle = 0;
+
+ switch (MSC_Handle->hbot.state)
+ {
+ case BOT_SEND_CBW:
+ MSC_Handle->hbot.cbw.field.LUN = lun;
+ MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT;
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.cbw.data,
+ BOT_CBW_LENGTH,
+ MSC_Handle->OutPipe,
+ 1);
+ break;
+
+ case BOT_SEND_CBW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ if ( MSC_Handle->hbot.cbw.field.DataTransferLength != 0 )
+ {
+ /* If there is Data Transfer Stage */
+ if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H)
+ {
+ /* Data Direction is IN */
+ MSC_Handle->hbot.state = BOT_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+ }
+ }
+
+ else
+ {/* If there is NO Data Transfer Stage */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+
+ }
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send CBW */
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+ }
+ break;
+
+ case BOT_DATA_IN:
+ if (MSC_Handle->hbot.pbuf != NULL)
+ {
+ //Simple single-buffer operation
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT;
+ MSC_Handle->hbot.this_URB_size = MIN(MSC_Handle->hbot.cbw.field.DataTransferLength,
+ MSC_Handle->InEpSize);
+ USBH_BulkReceiveData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->hbot.this_URB_size,
+ MSC_Handle->InPipe);
+ }
+ else
+ {
+ //Asynchronous multi-packet operation: get first packet
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT_FREE_PACKET;
+ Callback_MSC_phost = phost;
+ if (Downstream_GetFreePacket(USBH_MSC_BOT_Read_Multipacket_FreePacketCallback) != HAL_OK)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ }
+ }
+ break;
+
+ case BOT_DATA_IN_WAIT_FREE_PACKET:
+ break;
+
+ case BOT_DATA_IN_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ if (USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != MSC_Handle->hbot.this_URB_size)
+ {
+ while(1);
+ }
+
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->hbot.this_URB_size;
+
+ if (MSC_Handle->hbot.pbuf != NULL)
+ {
+ //Simple single-buffer operation: everything must fit in one URB
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+ else
+ {
+ //Asynchronous multi-packet operation
+ MSC_Handle->hbot.bot_packet_bytes_remaining -= MSC_Handle->hbot.this_URB_size;
+ MSC_Handle->hbot.bot_packet_pbuf += MSC_Handle->hbot.this_URB_size;
+
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength == 0)
+ {
+ //End of reception: dispatch last packet
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ Downstream_MSC_PutStreamDataPacket(MSC_Handle->hbot.bot_packet,
+ (BOT_PAGE_LENGTH - MSC_Handle->hbot.bot_packet_bytes_remaining));
+ }
+ else
+ {
+ //Still more data to receive
+// if (MSC_Handle->hbot.bot_packet_bytes_remaining == 0)
+// {
+ //Dispatch current bot_packet, then get a new one
+ if (Downstream_MSC_PutStreamDataPacket(MSC_Handle->hbot.bot_packet,
+ BOT_PAGE_LENGTH) != HAL_OK)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ break;
+ }
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT_FREE_PACKET;
+ if (Downstream_GetFreePacket(USBH_MSC_BOT_Read_Multipacket_FreePacketCallback) != HAL_OK)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ break;
+ }
+// }
+// else
+// {
+// //Continue filling the current bot_packet
+// USBH_MSC_BOT_Read_Multipacket_PrepareURB(phost);
+// }
+ }
+ }
+ }
+
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ /* This is Data IN Stage STALL Condition */
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.2 Host expects to receive data from the device
+ 3. On a STALL condition receiving data, then:
+ The host shall accept the data received.
+ The host shall clear the Bulk-In pipe.
+ 4. The host shall attempt to receive a CSW.*/
+ }
+ break;
+
+ case BOT_DATA_OUT:
+ if (MSC_Handle->hbot.pbuf != NULL)
+ {
+ //Simple single-buffer operation
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT;
+ MSC_Handle->hbot.this_URB_size = MIN(MSC_Handle->hbot.cbw.field.DataTransferLength,
+ MSC_Handle->OutEpSize);
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->hbot.this_URB_size,
+ MSC_Handle->OutPipe,
+ 1);
+ }
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ else
+ {
+ //Asynchronous multi-packet operation: get first packet
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT_RECEIVE_PACKET;
+ Callback_MSC_phost = phost;
+ if (Downstream_MSC_GetStreamDataPacket(USBH_MSC_BOT_Write_Multipacket_ReceivePacketCallback) != HAL_OK)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+ }
+ }
+#endif
+ break;
+
+ case BOT_DATA_OUT_WAIT_RECEIVE_PACKET:
+ break;
+
+ case BOT_DATA_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->hbot.this_URB_size;
+
+ if (MSC_Handle->hbot.pbuf != NULL)
+ {
+ //Simple single-buffer operation: everything must fit in one URB
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ else
+ {
+ //Asynchronous multi-packet operation
+ MSC_Handle->hbot.bot_packet_bytes_remaining -= MSC_Handle->hbot.this_URB_size;
+ MSC_Handle->hbot.bot_packet_pbuf += MSC_Handle->hbot.this_URB_size;
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength == 0)
+ {
+ //End of transmission
+ Downstream_ReleasePacket(MSC_Handle->hbot.bot_packet);
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+ else
+ {
+ //Still more data to send
+ if (MSC_Handle->hbot.bot_packet_bytes_remaining == 0)
+ {
+ //Get next bot_packet
+ Downstream_ReleasePacket(MSC_Handle->hbot.bot_packet);
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT_RECEIVE_PACKET;
+ if (Downstream_MSC_GetStreamDataPacket(USBH_MSC_BOT_Write_Multipacket_ReceivePacketCallback) != HAL_OK)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+ }
+ }
+ else
+ {
+ //Continue writing the current bot_packet
+ USBH_MSC_BOT_Write_Multipacket_PrepareURB(phost);
+ }
+ }
+ }
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Resend same data */
+ if (MSC_Handle->hbot.pbuf != NULL)
+ {
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+ }
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ else
+ {
+ //Increment counters by the amount of data actually transferred during the NAK'd URB
+ partialTransferLength = USBH_LL_GetLastXferSize(phost, MSC_Handle->OutPipe);
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= partialTransferLength;
+ MSC_Handle->hbot.bot_packet_bytes_remaining -= partialTransferLength;
+ MSC_Handle->hbot.bot_packet_pbuf += partialTransferLength;
+
+ USBH_MSC_BOT_Write_Multipacket_PrepareURB(phost);
+ }
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.3 Ho - Host expects to send data to the device
+ 3. On a STALL condition sending data, then:
+ " The host shall clear the Bulk-Out pipe.
+ 4. The host shall attempt to receive a CSW.
+ */
+ }
+ break;
+
+ case BOT_RECEIVE_CSW:
+
+ USBH_BulkReceiveData (phost,
+ MSC_Handle->hbot.csw.data,
+ BOT_CSW_LENGTH ,
+ MSC_Handle->InPipe);
+
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT;
+ break;
+
+ case BOT_RECEIVE_CSW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ /* Decode CSW */
+ if(URB_Status == USBH_URB_DONE)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+ CSW_Status = USBH_MSC_DecodeCSW(phost);
+
+ if(CSW_Status == BOT_CSW_CMD_PASSED)
+ {
+ status = USBH_OK;
+ }
+ else
+ {
+ status = USBH_FAIL;
+ }
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ }
+ break;
+
+ case BOT_ERROR_IN:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN);
+
+ if (error == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+ else if (error == USBH_UNRECOVERED_ERROR)
+ {
+ /* This means that there is a STALL Error limit, Do Reset Recovery */
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ break;
+
+ case BOT_ERROR_OUT:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT);
+
+ if ( error == USBH_OK)
+ {
+
+ toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe);
+ USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1- toggle);
+ USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0);
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ }
+ else if (error == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ break;
+
+
+ case BOT_UNRECOVERED_ERROR:
+ status = USBH_MSC_BOT_REQ_Reset(phost);
+ if ( status == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+
+void USBH_MSC_BOT_Read_Multipacket_FreePacketCallback(DownstreamPacketTypeDef* freePacket)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) Callback_MSC_phost->pActiveClass->pData;
+
+ if (MSC_Handle->hbot.state != BOT_DATA_IN_WAIT_FREE_PACKET)
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT;
+ MSC_Handle->hbot.bot_packet = freePacket;
+ MSC_Handle->hbot.bot_packet_pbuf = freePacket->Data;
+ MSC_Handle->hbot.bot_packet_bytes_remaining = BOT_PAGE_LENGTH;
+ USBH_MSC_BOT_Read_Multipacket_PrepareURB(Callback_MSC_phost);
+}
+
+
+void USBH_MSC_BOT_Read_Multipacket_PrepareURB(USBH_HandleTypeDef *phost)
+{
+ uint32_t temp_URB_size;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ temp_URB_size = MSC_Handle->hbot.cbw.field.DataTransferLength;
+ if (temp_URB_size > MSC_Handle->hbot.bot_packet_bytes_remaining)
+ {
+ temp_URB_size = MSC_Handle->hbot.bot_packet_bytes_remaining;
+ }
+// if (temp_URB_size > MSC_Handle->InEpSize)
+// {
+// temp_URB_size = MSC_Handle->InEpSize;
+// }
+ MSC_Handle->hbot.this_URB_size = (uint16_t)temp_URB_size;
+
+ USBH_BulkReceiveData(phost,
+ MSC_Handle->hbot.bot_packet_pbuf,
+ MSC_Handle->hbot.this_URB_size,
+ MSC_Handle->InPipe);
+}
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+void USBH_MSC_BOT_Write_Multipacket_ReceivePacketCallback(DownstreamPacketTypeDef* receivedPacket,
+ uint16_t dataLength)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) Callback_MSC_phost->pActiveClass->pData;
+
+ if (MSC_Handle->hbot.state != BOT_DATA_OUT_WAIT_RECEIVE_PACKET)
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT;
+ MSC_Handle->hbot.bot_packet = receivedPacket;
+ MSC_Handle->hbot.bot_packet_pbuf = receivedPacket->Data;
+ MSC_Handle->hbot.bot_packet_bytes_remaining = dataLength;
+ USBH_MSC_BOT_Write_Multipacket_PrepareURB(Callback_MSC_phost);
+}
+
+
+void USBH_MSC_BOT_Write_Multipacket_PrepareURB(USBH_HandleTypeDef *phost)
+{
+ uint32_t temp_URB_size;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ temp_URB_size = MSC_Handle->hbot.cbw.field.DataTransferLength;
+ if (temp_URB_size > MSC_Handle->hbot.bot_packet_bytes_remaining)
+ {
+ temp_URB_size = MSC_Handle->hbot.bot_packet_bytes_remaining;
+ }
+ if (temp_URB_size > MSC_Handle->OutEpSize)// * 4) //Some silicon has a buggy host fifo, so we write single packets only :(
+ {
+ temp_URB_size = MSC_Handle->OutEpSize;// * 4;
+ }
+ MSC_Handle->hbot.this_URB_size = (uint16_t)temp_URB_size;
+
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.bot_packet_pbuf,
+ MSC_Handle->hbot.this_URB_size,
+ MSC_Handle->OutPipe,
+ 1);
+}
+#endif
+
+/**
+ * @brief USBH_MSC_BOT_Abort
+ * The function handle the BOT Abort process.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param dir: direction (0: out / 1 : in)
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir)
+{
+ UNUSED(lun);
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (dir)
+ {
+ case BOT_DIR_IN :
+ /* send ClrFeture on Bulk IN endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->InEp);
+
+ break;
+
+ case BOT_DIR_OUT :
+ /*send ClrFeature on Bulk OUT endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->OutEp);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_BOT_DecodeCSW
+ * This function decodes the CSW received by the device and updates the
+ * same to upper layer.
+ * @param phost: Host handle
+ * @retval USBH Status
+ * @notes
+ * Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ * 6.3.1 Valid CSW Conditions :
+ * The host shall consider the CSW valid when:
+ * 1. dCSWSignature is equal to 53425355h
+ * 2. the CSW is 13 (Dh) bytes in length,
+ * 3. dCSWTag matches the dCBWTag from the corresponding CBW.
+ */
+
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ BOT_CSWStatusTypeDef status = BOT_CSW_CMD_FAILED;
+
+ /*Checking if the transfer length is different than 13*/
+ if(USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != BOT_CSW_LENGTH)
+ {
+ /*(4) Hi > Dn (Host expects to receive data from the device,
+ Device intends to transfer no data)
+ (5) Hi > Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (9) Ho > Dn (Host expects to send data to the device,
+ Device intends to transfer no data)
+ (11) Ho > Do (Host expects to send data to the device,
+ Device intends to receive data from the host)*/
+
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ else
+ { /* CSW length is Correct */
+
+ /* Check validity of the CSW Signature and CSWStatus */
+ if(MSC_Handle->hbot.csw.field.Signature == BOT_CSW_SIGNATURE)
+ {/* Check Condition 1. dCSWSignature is equal to 53425355h */
+
+ if(MSC_Handle->hbot.csw.field.Tag == MSC_Handle->hbot.cbw.field.Tag)
+ {
+ /* Check Condition 3. dCSWTag matches the dCBWTag from the
+ corresponding CBW */
+
+ if(MSC_Handle->hbot.csw.field.Status == 0)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+
+ Hn Host expects no data transfers
+ Hi Host expects to receive data from the device
+ Ho Host expects to send data to the device
+
+ Dn Device intends to transfer no data
+ Di Device intends to send data to the host
+ Do Device intends to receive data from the host
+
+ Section 6.7
+ (1) Hn = Dn (Host expects no data transfers,
+ Device intends to transfer no data)
+ (6) Hi = Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (12) Ho = Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+
+ */
+
+ status = BOT_CSW_CMD_PASSED;
+ }
+ else if(MSC_Handle->hbot.csw.field.Status == 1)
+ {
+ status = BOT_CSW_CMD_FAILED;
+ }
+
+ else if(MSC_Handle->hbot.csw.field.Status == 2)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ Section 6.7
+ (2) Hn < Di ( Host expects no data transfers,
+ Device intends to send data to the host)
+ (3) Hn < Do ( Host expects no data transfers,
+ Device intends to receive data from the host)
+ (7) Hi < Di ( Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (8) Hi <> Do ( Host expects to receive data from the device,
+ Device intends to receive data from the host)
+ (10) Ho <> Di (Host expects to send data to the device,
+ Di Device intends to send data to the host)
+ (13) Ho < Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+ */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ } /* CSW Tag Matching is Checked */
+ } /* CSW Signature Correct Checking */
+ else
+ {
+ /* If the CSW Signature is not valid, We sall return the Phase Error to
+ Upper Layers for Reset Recovery */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ } /* CSW Length Check*/
+
+ return status;
+}
+
+#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.c
new file mode 100644
index 0000000..8028139
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.c
@@ -0,0 +1,473 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements the SCSI commands
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_msc.h"
+#include "usbh_msc_scsi.h"
+#include "usbh_msc_bot.h"
+#include "build_config.h"
+
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_SCSI_TestUnitReady
+ * Issue TestUnitReady command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
+ uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if (MSC_Handle->hbot.cmd_state == BOT_CMD_SEND)
+ {
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_TEST_UNIT_READY;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ }
+
+ return USBH_MSC_BOT_Process(phost, lun);
+}
+
+/**
+ * @brief USBH_MSC_SCSI_ReadCapacity
+ * Issue Read Capacity command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the capacity structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity)
+{
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ_CAPACITY10;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if(error == USBH_OK)
+ {
+ /*assign the capacity*/
+ capacity->block_nbr = (MSC_Handle->hbot.pbuf[3] | (MSC_Handle->hbot.pbuf[2] << 8) |\
+ (MSC_Handle->hbot.pbuf[1] << 16) | (MSC_Handle->hbot.pbuf[0] << 24)) + 1; //block_nbr = logical address of last block + 1
+
+ /*assign the page length*/
+ capacity->block_size = MSC_Handle->hbot.pbuf[7] | (MSC_Handle->hbot.pbuf[6] << 8);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Inquiry
+ * Issue Inquiry command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the inquiry structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_INQUIRY;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0;
+ MSC_Handle->hbot.cbw.field.CB[4] = 0x24;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if(error == USBH_OK)
+ {
+ USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef));
+ /*assign Inquiry Data */
+ inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1F;
+ inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5;
+ inquiry->RemovableMedia = (MSC_Handle->hbot.pbuf[1] & 0x80)== 0x80;
+ USBH_memcpy (inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8);
+ USBH_memcpy (inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16);
+ USBH_memcpy (inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_RequestSense
+ * Issue RequestSense command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the sense data structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0;
+ MSC_Handle->hbot.cbw.field.CB[4] = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+ if (error == USBH_OK)
+ {
+ sense_data->key = MSC_Handle->hbot.pbuf[2] & 0x0F;
+ sense_data->asc = MSC_Handle->hbot.pbuf[12];
+ sense_data->ascq = MSC_Handle->hbot.pbuf[13];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Write
+ * Issue write10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * MSC_Handle->unit[lun].capacity.block_size;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_WRITE10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
+
+ /*Transfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = NULL;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+#endif
+
+/**
+ * @brief USBH_MSC_SCSI_Read
+ * Issue Read10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+ /*Prepare the CBW and relevant fields*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * MSC_Handle->unit[lun].capacity.block_size;;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
+
+ /*Transfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = NULL;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+
+USBH_StatusTypeDef USBH_MSC_SCSI_StartStopUnit(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint8_t startStop)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if (MSC_Handle->hbot.cmd_state == BOT_CMD_SEND)
+ {
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_START_STOP_UNIT;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_START_STOP_UNIT;
+ MSC_Handle->hbot.cbw.field.CB[4] = 0x02 | (startStop & 0x01); //LOEJ = 1, START = 0 for eject, START = 1 for load
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ }
+
+ return USBH_MSC_BOT_Process(phost, lun);
+}
+
+
+#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_core.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_core.h
new file mode 100644
index 0000000..c9d913d
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_core.h
@@ -0,0 +1,170 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_core.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_CORE_H
+#define __USBH_CORE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_config.h"
+#include "usbh_def.h"
+#include "usbh_ioreq.h"
+#include "usbh_pipes.h"
+#include "usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CORE
+ * @brief This file is the Header file for usbh_core.c
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Exported_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+#define HOST_USER_SELECT_CONFIGURATION 1
+#define HOST_USER_CLASS_ACTIVE 2
+#define HOST_USER_CLASS_SELECTED 3
+#define HOST_USER_CONNECTION 4
+#define HOST_USER_DISCONNECTION 5
+#define HOST_USER_UNRECOVERED_ERROR 6
+#define HOST_USER_CLASS_FAILED 7
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id);
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass);
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface);
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost,
+ uint8_t Class,
+ uint8_t SubClass,
+ uint8_t Protocol);
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost);
+
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost,
+ uint8_t interface_number,
+ uint8_t alt_settings);
+
+USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Process (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost);
+
+/* USBH Low Level Driver */
+USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Start (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_PortEnabled (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost);
+USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost);
+uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t );
+USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t );
+
+USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost, uint8_t, uint8_t, uint8_t, uint8_t , uint8_t, uint16_t );
+USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t );
+USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost, uint8_t, uint8_t,uint8_t, uint8_t, uint8_t*, uint16_t, uint8_t );
+USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t );
+#if (USBH_USE_OS == 1)
+USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost);
+#endif
+USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t , uint8_t );
+uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t );
+
+/* USBH Time base */
+void USBH_Delay (uint32_t Delay);
+void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t );
+void USBH_LL_IncTimer (USBH_HandleTypeDef *phost);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_CORE_H */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h
new file mode 100644
index 0000000..1284a55
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h
@@ -0,0 +1,159 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_ctlreq.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_CTLREQ_H
+#define __USBH_CTLREQ_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+ * @brief This file is the
+ * @{
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Defines
+ * @{
+ */
+/*Standard Feature Selector for clear feature command*/
+#define FEATURE_SELECTOR_ENDPOINT 0X00
+#define FEATURE_SELECTOR_DEVICE 0X01
+
+
+#define INTERFACE_DESC_TYPE 0x04
+#define ENDPOINT_DESC_TYPE 0x05
+#define INTERFACE_DESC_SIZE 0x09
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_Variables
+ * @{
+ */
+//extern uint8_t USBH_CfgDesc[512];
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type,
+ uint16_t type_idx,
+ uint16_t value,
+ uint8_t* buff,
+ uint16_t length );
+
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index,
+ uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
+ uint16_t configuration_value);
+
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress);
+
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
+ uint8_t ep_num, uint8_t altSetting);
+
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
+ uint8_t ep_num);
+
+USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf,
+ uint16_t *ptr);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_CTLREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h
new file mode 100644
index 0000000..93521e2
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_def.h
@@ -0,0 +1,503 @@
+/**
+ ******************************************************************************
+ * @file usbh_def.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Definitions used in the USB host library
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef USBH_DEF_H
+#define USBH_DEF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_config.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_DEF
+ * @brief This file is includes USB descriptors
+ * @{
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+#define ValBit(VAR,POS) (VAR & (1 << POS))
+#define SetBit(VAR,POS) (VAR |= (1 << POS))
+#define ClrBit(VAR,POS) (VAR &= ((1 << POS)^255))
+
+#define LE16(addr) (((uint16_t)(*((uint8_t *)(addr))))\
+ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
+
+#define LE16S(addr) (uint16_t)(LE16((addr)))
+
+#define LE32(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 3))) << 24)))
+
+#define LE64(addr) ((((uint64_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint64_t)(*(((uint8_t *)(addr)) + 1))) << 8) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 2))) << 16) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 3))) << 24) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 4))) << 32) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 5))) << 40) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 6))) << 48) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 7))) << 56)))
+
+
+#define LE24(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16)))
+
+
+#define LE32S(addr) (int32_t)(LE32((addr)))
+
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+
+#define USB_LEN_DESC_HDR 0x02
+#define USB_LEN_DEV_DESC 0x12
+#define USB_LEN_CFG_DESC 0x09
+#define USB_LEN_IF_DESC 0x09
+#define USB_LEN_EP_DESC 0x07
+#define USB_LEN_OTG_DESC 0x03
+#define USB_LEN_SETUP_PKT 0x08
+
+/* bmRequestType :D7 Data Phase Transfer Direction */
+#define USB_REQ_DIR_MASK 0x80
+#define USB_H2D 0x00
+#define USB_D2H 0x80
+
+/* bmRequestType D6..5 Type */
+#define USB_REQ_TYPE_STANDARD 0x00
+#define USB_REQ_TYPE_CLASS 0x20
+#define USB_REQ_TYPE_VENDOR 0x40
+#define USB_REQ_TYPE_RESERVED 0x60
+
+/* bmRequestType D4..0 Recipient */
+#define USB_REQ_RECIPIENT_DEVICE 0x00
+#define USB_REQ_RECIPIENT_INTERFACE 0x01
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02
+#define USB_REQ_RECIPIENT_OTHER 0x03
+
+/* Table 9-4. Standard Request Codes */
+/* bRequest , Value */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+/* Table 9-5. Descriptor Types of USB Specifications */
+#define USB_DESC_TYPE_DEVICE 1
+#define USB_DESC_TYPE_CONFIGURATION 2
+#define USB_DESC_TYPE_STRING 3
+#define USB_DESC_TYPE_INTERFACE 4
+#define USB_DESC_TYPE_ENDPOINT 5
+#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
+#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
+#define USB_DESC_TYPE_INTERFACE_POWER 8
+#define USB_DESC_TYPE_HID 0x21
+#define USB_DESC_TYPE_HID_REPORT 0x22
+
+
+#define USB_DEVICE_DESC_SIZE 18
+#define USB_CONFIGURATION_DESC_SIZE 9
+#define USB_HID_DESC_SIZE 9
+#define USB_INTERFACE_DESC_SIZE 9
+#define USB_ENDPOINT_DESC_SIZE 7
+
+/* Descriptor Type and Descriptor Index */
+/* Use the following values when calling the function USBH_GetDescriptor */
+#define USB_DESC_DEVICE ((USB_DESC_TYPE_DEVICE << 8) & 0xFF00)
+#define USB_DESC_CONFIGURATION ((USB_DESC_TYPE_CONFIGURATION << 8) & 0xFF00)
+#define USB_DESC_STRING ((USB_DESC_TYPE_STRING << 8) & 0xFF00)
+#define USB_DESC_INTERFACE ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
+#define USB_DESC_ENDPOINT ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
+#define USB_DESC_DEVICE_QUALIFIER ((USB_DESC_TYPE_DEVICE_QUALIFIER << 8) & 0xFF00)
+#define USB_DESC_OTHER_SPEED_CONFIGURATION ((USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION << 8) & 0xFF00)
+#define USB_DESC_INTERFACE_POWER ((USB_DESC_TYPE_INTERFACE_POWER << 8) & 0xFF00)
+#define USB_DESC_HID_REPORT ((USB_DESC_TYPE_HID_REPORT << 8) & 0xFF00)
+#define USB_DESC_HID ((USB_DESC_TYPE_HID << 8) & 0xFF00)
+
+
+#define USB_EP_TYPE_CTRL 0x00
+#define USB_EP_TYPE_ISOC 0x01
+#define USB_EP_TYPE_BULK 0x02
+#define USB_EP_TYPE_INTR 0x03
+
+#define USB_EP_DIR_OUT 0x00
+#define USB_EP_DIR_IN 0x80
+#define USB_EP_DIR_MSK 0x80
+
+#ifndef USBH_MAX_PIPES_NBR
+ #define USBH_MAX_PIPES_NBR 15
+#endif /* USBH_MAX_PIPES_NBR */
+
+#define USBH_DEVICE_ADDRESS_DEFAULT 0
+#define USBH_MAX_ERROR_COUNT 10
+#define USBH_DEVICE_ADDRESS 1
+
+#define USBH_CTRL_TRANSACTION_TIMEOUT_MS 200
+
+
+/**
+ * @}
+ */
+
+
+#define USBH_CONFIGURATION_DESCRIPTOR_SIZE (USB_CONFIGURATION_DESC_SIZE \
+ + USB_INTERFACE_DESC_SIZE\
+ + (USBH_MAX_NUM_ENDPOINTS * USB_ENDPOINT_DESC_SIZE))
+
+
+#define CONFIG_DESC_wTOTAL_LENGTH (ConfigurationDescriptorData.ConfigDescfield.\
+ ConfigurationDescriptor.wTotalLength)
+
+
+typedef union
+{
+ uint16_t w;
+ struct BW
+ {
+ uint8_t msb;
+ uint8_t lsb;
+ }
+ bw;
+}
+uint16_t_uint8_t;
+
+
+typedef union _USB_Setup
+{
+ uint32_t d8[2];
+
+ struct _SetupPkt_Struc
+ {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t_uint8_t wValue;
+ uint16_t_uint8_t wIndex;
+ uint16_t_uint8_t wLength;
+ } b;
+}
+USB_Setup_TypeDef;
+
+typedef struct _DescHeader
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+}
+USBH_DescHeader_t;
+
+typedef struct _DeviceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB; /* USB Specification Number which device complies too */
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ /* If equal to Zero, each interface specifies its own class
+ code if equal to 0xFF, the class code is vendor specified.
+ Otherwise field is valid Class Code.*/
+ uint8_t bMaxPacketSize;
+ uint16_t idVendor; /* Vendor ID (Assigned by USB Org) */
+ uint16_t idProduct; /* Product ID (Assigned by Manufacturer) */
+ uint16_t bcdDevice; /* Device Release Number */
+ uint8_t iManufacturer; /* Index of Manufacturer String Descriptor */
+ uint8_t iProduct; /* Index of Product String Descriptor */
+ uint8_t iSerialNumber; /* Index of Serial Number String Descriptor */
+ uint8_t bNumConfigurations; /* Number of Possible Configurations */
+}
+USBH_DevDescTypeDef;
+
+typedef struct _EndpointDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress; /* indicates what endpoint this descriptor is describing */
+ uint8_t bmAttributes; /* specifies the transfer type. */
+ uint16_t wMaxPacketSize; /* Maximum Packet Size this endpoint is capable of sending or receiving */
+ uint8_t bInterval; /* is used to specify the polling interval of certain transfers. */
+}
+USBH_EpDescTypeDef;
+
+typedef struct _InterfaceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting; /* Value used to select alternative setting */
+ uint8_t bNumEndpoints; /* Number of Endpoints used for this interface */
+ uint8_t bInterfaceClass; /* Class Code (Assigned by USB Org) */
+ uint8_t bInterfaceSubClass; /* Subclass Code (Assigned by USB Org) */
+ uint8_t bInterfaceProtocol; /* Protocol Code */
+ uint8_t iInterface; /* Index of String Descriptor Describing this interface */
+ USBH_EpDescTypeDef Ep_Desc[USBH_MAX_NUM_ENDPOINTS];
+}
+USBH_InterfaceDescTypeDef;
+
+
+typedef struct _ConfigurationDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength; /* Total Length of Data Returned */
+ uint8_t bNumInterfaces; /* Number of Interfaces */
+ uint8_t bConfigurationValue; /* Value to use as an argument to select this configuration*/
+ uint8_t iConfiguration; /*Index of String Descriptor Describing this configuration */
+ uint8_t bmAttributes; /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/
+ uint8_t bMaxPower; /*Maximum Power Consumption */
+ USBH_InterfaceDescTypeDef Itf_Desc[USBH_MAX_NUM_INTERFACES];
+}
+USBH_CfgDescTypeDef;
+
+
+/* Following USB Host status */
+typedef enum
+{
+ USBH_OK = 0,
+ USBH_BUSY,
+ USBH_FAIL,
+ USBH_NOT_SUPPORTED,
+ USBH_UNRECOVERED_ERROR,
+ USBH_ERROR_SPEED_UNKNOWN,
+}USBH_StatusTypeDef;
+
+
+/** @defgroup USBH_CORE_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ USBH_SPEED_HIGH = 0,
+ USBH_SPEED_FULL = 1,
+ USBH_SPEED_LOW = 2,
+
+}USBH_SpeedTypeDef;
+
+/* Following states are used for gState */
+typedef enum
+{
+ HOST_IDLE =0,
+ HOST_DEV_WAIT_FOR_ATTACHMENT,
+ HOST_DEV_ATTACHED,
+ HOST_DEV_DISCONNECTED,
+ HOST_DETECT_DEVICE_SPEED,
+ HOST_ENUMERATION,
+ HOST_CLASS_REQUEST,
+ HOST_INPUT,
+ HOST_SET_CONFIGURATION,
+ HOST_CHECK_CLASS,
+ HOST_CLASS,
+ HOST_SUSPENDED,
+ HOST_ABORT_STATE,
+}HOST_StateTypeDef;
+
+/* Following states are used for EnumerationState */
+typedef enum
+{
+ ENUM_IDLE = 0,
+ ENUM_GET_FULL_DEV_DESC,
+ ENUM_SET_ADDR,
+ ENUM_GET_CFG_DESC,
+ ENUM_GET_FULL_CFG_DESC,
+ ENUM_GET_MFC_STRING_DESC,
+ ENUM_GET_PRODUCT_STRING_DESC,
+ ENUM_GET_SERIALNUM_STRING_DESC,
+} ENUM_StateTypeDef;
+
+/* Following states are used for CtrlXferStateMachine */
+typedef enum
+{
+ CTRL_IDLE =0,
+ CTRL_SETUP,
+ CTRL_SETUP_WAIT,
+ CTRL_DATA_IN,
+ CTRL_DATA_IN_WAIT,
+ CTRL_DATA_OUT,
+ CTRL_DATA_OUT_WAIT,
+ CTRL_STATUS_IN,
+ CTRL_STATUS_IN_WAIT,
+ CTRL_STATUS_OUT,
+ CTRL_STATUS_OUT_WAIT,
+ CTRL_ERROR,
+ CTRL_STALLED,
+ CTRL_COMPLETE
+}CTRL_StateTypeDef;
+
+
+/* Following states are used for RequestState */
+typedef enum
+{
+ CMD_IDLE =0,
+ CMD_SEND,
+ CMD_WAIT
+} CMD_StateTypeDef;
+
+typedef enum {
+ USBH_URB_IDLE = 0,
+ USBH_URB_DONE,
+ USBH_URB_NOTREADY,
+ USBH_URB_NYET,
+ USBH_URB_ERROR,
+ USBH_URB_STALL
+}USBH_URBStateTypeDef;
+
+typedef enum
+{
+ USBH_PORT_EVENT = 1,
+ USBH_URB_EVENT,
+ USBH_CONTROL_EVENT,
+ USBH_CLASS_EVENT,
+ USBH_STATE_CHANGED_EVENT,
+}
+USBH_OSEventTypeDef;
+
+/* Control request structure */
+typedef struct
+{
+ uint8_t pipe_in;
+ uint8_t pipe_out;
+ uint8_t pipe_size;
+ uint8_t *buff;
+ uint32_t timer;
+ uint16_t length;
+ USB_Setup_TypeDef setup;
+ CTRL_StateTypeDef state;
+ uint8_t errorcount;
+
+} USBH_CtrlTypeDef;
+
+/* Attached device structure */
+typedef struct
+{
+#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
+ uint8_t CfgDesc_Raw[USBH_MAX_SIZE_CONFIGURATION];
+#endif
+ uint8_t Data[USBH_MAX_DATA_BUFFER];
+ uint8_t address;
+ uint8_t speed;
+ __IO uint8_t is_connected;
+ uint8_t current_interface;
+ USBH_DevDescTypeDef DevDesc;
+ USBH_CfgDescTypeDef CfgDesc;
+
+}USBH_DeviceTypeDef;
+
+struct _USBH_HandleTypeDef;
+
+/* USB Host Class structure */
+typedef struct
+{
+ const char *Name;
+ uint8_t ClassCode;
+ USBH_StatusTypeDef (*Init) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*DeInit) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*Requests) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*BgndProcess) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*SOFProcess) (struct _USBH_HandleTypeDef *phost);
+ void* pData;
+} USBH_ClassTypeDef;
+
+
+
+#define HOST_PIPE_COUNT 15
+
+
+/* USB Host handle structure */
+typedef struct _USBH_HandleTypeDef
+{
+ __IO HOST_StateTypeDef gState; /* Host State Machine Value */
+ ENUM_StateTypeDef EnumState; /* Enumeration state Machine */
+ CMD_StateTypeDef RequestState;
+ USBH_CtrlTypeDef Control;
+ USBH_DeviceTypeDef device;
+ USBH_ClassTypeDef* pClass[USBH_MAX_NUM_SUPPORTED_CLASS];
+ USBH_ClassTypeDef* pActiveClass;
+ uint32_t ClassNumber;
+ uint32_t Pipes[HOST_PIPE_COUNT];
+ __IO uint32_t Timer;
+ uint8_t id;
+ void* pData;
+ void (* pUser )(struct _USBH_HandleTypeDef *pHandle, uint8_t id);
+
+#if (USBH_USE_OS == 1)
+ osMessageQId os_event;
+ osThreadId thread;
+#endif
+
+} USBH_HandleTypeDef;
+
+
+#if defined ( __GNUC__ )
+ #ifndef __weak
+ #define __weak __attribute__((weak))
+ #endif /* __weak */
+ #ifndef __packed
+ #define __packed __attribute__((__packed__))
+ #endif /* __packed */
+#endif /* __GNUC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_DEF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h
new file mode 100644
index 0000000..ab9029a
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h
@@ -0,0 +1,168 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_ioreq.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_IOREQ_H
+#define __USBH_IOREQ_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_config.h"
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file is the header file for usbh_ioreq.c
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Defines
+ * @{
+ */
+
+#define USBH_PID_SETUP 0
+#define USBH_PID_DATA 1
+
+#define USBH_EP_CONTROL 0
+#define USBH_EP_ISO 1
+#define USBH_EP_BULK 2
+#define USBH_EP_INTERRUPT 3
+
+#define USBH_SETUP_PKT_SIZE 8
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num,
+ uint8_t do_ping );
+
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num,
+ uint8_t do_ping );
+
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t hc_num);
+
+
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t hc_num);
+
+
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t hc_num);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_IOREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h
new file mode 100644
index 0000000..16aa438
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h
@@ -0,0 +1,131 @@
+/**
+ ******************************************************************************
+ * @file usbh_pipes.h
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief Header file for usbh_pipes.c
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_PIPES_H
+#define __USBH_PIPES_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file is the header file for usbh_pipes.c
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t ch_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps);
+
+USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num);
+
+uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost,
+ uint8_t ep_addr);
+
+USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost,
+ uint8_t idx);
+
+
+
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_PIPES_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_conf_template.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_conf_template.c
new file mode 100644
index 0000000..ee63c80
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_conf_template.c
@@ -0,0 +1,271 @@
+/**
+ ******************************************************************************
+ * @file usb_bsp.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements the board support package for the USB host library
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/**
+ * @brief USBH_LL_Init
+ * Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_DeInit
+ * De-Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Start
+ * Start the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Stop
+ * Stop the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetSpeed
+ * Return the USB Host Speed from the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Speeds
+ */
+USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost)
+{
+ USBH_SpeedTypeDef speed = USBH_SPEED_FULL;
+
+
+ return speed;
+}
+
+/**
+ * @brief USBH_LL_ResetPort
+ * Reset the Host Port of the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetLastXferSize
+ * Return the last transferred packet size.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval Packet Size
+ */
+uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return 0;
+}
+
+/**
+ * @brief USBH_LL_OpenPipe
+ * Open a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @param epnum: Endpoint Number
+ * @param dev_address: Device USB address
+ * @param speed: Device Speed
+ * @param ep_type: Endpoint Type
+ * @param mps: Endpoint Max Packet Size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_ClosePipe
+ * Close a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SubmitURB
+ * Submit a new URB to the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @param direction : Channel number
+ * This parameter can be one of the these values:
+ * 0 : Output
+ * 1 : Input
+ * @param ep_type : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg EP_TYPE_CTRL: Control type
+ * @arg EP_TYPE_ISOC: Isochronous type
+ * @arg EP_TYPE_BULK: Bulk type
+ * @arg EP_TYPE_INTR: Interrupt type
+ * @param token : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg 0: PID_SETUP
+ * @arg 1: PID_DATA
+ * @param pbuff : pointer to URB data
+ * @param length : Length of URB data
+ * @param do_ping : activate do ping protocol (for high speed only)
+ * This parameter can be one of the these values:
+ * 0 : do ping inactive
+ * 1 : do ping active
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t direction ,
+ uint8_t ep_type,
+ uint8_t token,
+ uint8_t* pbuff,
+ uint16_t length,
+ uint8_t do_ping )
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetURBState
+ * Get a URB state from the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @retval URB state
+ * This parameter can be one of the these values:
+ * @arg URB_IDLE
+ * @arg URB_DONE
+ * @arg URB_NOTREADY
+ * @arg URB_NYET
+ * @arg URB_ERROR
+ * @arg URB_STALL
+ */
+USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return USBH_URB_IDLE;
+}
+
+/**
+ * @brief USBH_LL_DriverVBUS
+ * Drive VBUS.
+ * @param phost: Host handle
+ * @param state : VBUS state
+ * This parameter can be one of the these values:
+ * 0 : VBUS Active
+ * 1 : VBUS Inactive
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t state)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SetToggle
+ * Set toggle for a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @param pipe_num: Pipe index
+ * @param toggle: toggle (0/1)
+ * @retval Status
+ */
+USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetToggle
+ * Return the current toggle of a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval toggle (0/1)
+ */
+uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ uint8_t toggle = 0;
+
+
+ return toggle;
+}
+/**
+ * @brief USBH_Delay
+ * Delay routine for the USB Host Library
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBH_Delay (uint32_t Delay)
+{
+
+}
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c
new file mode 100644
index 0000000..7235146
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c
@@ -0,0 +1,962 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements the functions for the core state machine process
+ * the enumeration and the control transfer process
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+/* Includes ------------------------------------------------------------------*/
+
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+ * @{
+ */
+
+/** @defgroup USBH_CORE
+ * @brief This file handles the basic enumeration when a device is connected
+ * to the host.
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Private_Defines
+ * @{
+ */
+#define USBH_ADDRESS_DEFAULT 0
+#define USBH_ADDRESS_ASSIGNED 1
+#define USBH_MPS_DEFAULT 0x40
+
+#define USBH_ATTACH_DELAY_MS 200
+#define USBH_DETACH_DELAY_MS 500
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Functions
+ * @{
+ */
+static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost);
+static void USBH_HandleSof (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost);
+
+#if (USBH_USE_OS == 1)
+static void USBH_Process_OS(void const * argument);
+#endif
+
+/**
+ * @brief HCD_Init
+ * Initialize the HOST Core.
+ * @param phost: Host Handle
+ * @param pUsrFunc: User Callback
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id)
+{
+ /* Check whether the USB Host handle is valid */
+ if(phost == NULL)
+ {
+ USBH_ErrLog("Invalid Host handle");
+ return USBH_FAIL;
+ }
+
+ /* Set DRiver ID */
+ phost->id = id;
+
+ /* Unlink class*/
+ phost->pActiveClass = NULL;
+ phost->ClassNumber = 0;
+
+ /* Restore default states and prepare EP0 */
+ DeInitStateMachine(phost);
+
+ /* Assign User process */
+ if(pUsrFunc != NULL)
+ {
+ phost->pUser = pUsrFunc;
+ }
+
+#if (USBH_USE_OS == 1)
+
+ /* Create USB Host Queue */
+ osMessageQDef(USBH_Queue, 10, uint16_t);
+ phost->os_event = osMessageCreate (osMessageQ(USBH_Queue), NULL);
+
+ /*Create USB Host Task */
+#if defined (USBH_PROCESS_STACK_SIZE)
+ osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, USBH_PROCESS_STACK_SIZE);
+#else
+ osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, 8 * configMINIMAL_STACK_SIZE);
+#endif
+ phost->thread = osThreadCreate (osThread(USBH_Thread), phost);
+#endif
+
+ /* Initialize low level driver */
+ USBH_LL_Init(phost);
+ return USBH_OK;
+}
+
+/**
+ * @brief HCD_Init
+ * De-Initialize the Host portion of the driver.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
+{
+ DeInitStateMachine(phost);
+
+ if(phost->pData != NULL)
+ {
+ phost->pActiveClass->pData = NULL;
+ USBH_LL_Stop(phost);
+ }
+
+ USBH_LL_DeInit(phost);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief DeInitStateMachine
+ * De-Initialize the Host state machine.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
+{
+ uint32_t i = 0;
+
+ /* Clear Pipes flags*/
+ for ( ; i < USBH_MAX_PIPES_NBR; i++)
+ {
+ phost->Pipes[i] = 0;
+ }
+
+ for(i = 0; i< USBH_MAX_DATA_BUFFER; i++)
+ {
+ phost->device.Data[i] = 0;
+ }
+
+ phost->gState = HOST_IDLE;
+ phost->EnumState = ENUM_IDLE;
+ phost->RequestState = CMD_SEND;
+ phost->Timer = 0;
+
+ phost->Control.state = CTRL_SETUP;
+ phost->Control.pipe_size = USBH_MPS_DEFAULT;
+ phost->Control.errorcount = 0;
+
+ phost->device.address = USBH_ADDRESS_DEFAULT;
+ phost->device.speed = USBH_SPEED_FULL;
+ phost->device.is_connected = 0;
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_RegisterClass
+ * Link class driver to Host Core.
+ * @param phost : Host Handle
+ * @param pclass: Class handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if(pclass != 0)
+ {
+ if(phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS)
+ {
+ /* link the class to the USB Host handle */
+ phost->pClass[phost->ClassNumber++] = pclass;
+ status = USBH_OK;
+ }
+ else
+ {
+ USBH_ErrLog("Max Class Number reached");
+ status = USBH_FAIL;
+ }
+ }
+ else
+ {
+ USBH_ErrLog("Invalid Class handle");
+ status = USBH_FAIL;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_SelectInterface
+ * Select current interface.
+ * @param phost: Host Handle
+ * @param interface: Interface number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if(interface < phost->device.CfgDesc.bNumInterfaces)
+ {
+ phost->device.current_interface = interface;
+ USBH_UsrLog ("Switching to Interface (#%d)", interface);
+ USBH_UsrLog ("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass );
+ USBH_UsrLog ("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass );
+ USBH_UsrLog ("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol );
+ }
+ else
+ {
+ USBH_ErrLog ("Cannot Select This Interface.");
+ status = USBH_FAIL;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_GetActiveClass
+ * Return Device Class.
+ * @param phost: Host Handle
+ * @param interface: Interface index
+ * @retval Class Code
+ */
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost)
+{
+ return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass);
+}
+/**
+ * @brief USBH_FindInterface
+ * Find the interface index for a specific class.
+ * @param phost: Host Handle
+ * @param Class: Class code
+ * @param SubClass: SubClass code
+ * @param Protocol: Protocol code
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_CfgDescTypeDef *pcfg ;
+ int8_t if_ix = 0;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if(((pif->bInterfaceClass == Class) || (Class == 0xFF))&&
+ ((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFF))&&
+ ((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFF)))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_FindInterfaceIndex
+ * Find the interface index for a specific class interface and alternate setting number.
+ * @param phost: Host Handle
+ * @param interface_number: interface number
+ * @param alt_settings : alternate setting number
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_CfgDescTypeDef *pcfg ;
+ int8_t if_ix = 0;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_Start
+ * Start the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost)
+{
+ /* Start the low level driver */
+ USBH_LL_Start(phost);
+
+ /* Activate VBUS on the port */
+ USBH_LL_DriverVBUS (phost, TRUE);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_Stop
+ * Stop the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost)
+{
+ /* Stop and cleanup the low level driver */
+ USBH_LL_Stop(phost);
+
+ /* DeActivate VBUS on the port */
+ USBH_LL_DriverVBUS (phost, FALSE);
+
+ /* FRee Control Pipes */
+ USBH_FreePipe (phost, phost->Control.pipe_in);
+ USBH_FreePipe (phost, phost->Control.pipe_out);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief HCD_ReEnumerate
+ * Perform a new Enumeration phase.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost)
+{
+ /*Stop Host */
+ USBH_Stop(phost);
+
+ /*Device has disconnected, so wait for 200 ms */
+ USBH_Delay(200);
+
+ /* Set State machines in default state */
+ DeInitStateMachine(phost);
+
+ /* Start again the host */
+ USBH_Start(phost);
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_Process
+ * Background process of the USB Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost)
+{
+ __IO USBH_StatusTypeDef status = USBH_FAIL;
+ uint8_t idx = 0;
+
+ switch (phost->gState)
+ {
+ case HOST_IDLE:
+
+ if (phost->device.is_connected)
+ {
+ /* Wait for 200 ms after connection */
+ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
+ USBH_Delay(USBH_ATTACH_DELAY_MS);
+ USBH_LL_ResetPort(phost);
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+ }
+ break;
+
+ case HOST_DEV_WAIT_FOR_ATTACHMENT:
+ break;
+
+ case HOST_DEV_ATTACHED :
+
+ USBH_UsrLog("USB Device Attached");
+
+ /* Wait for 100 ms after Reset */
+ USBH_Delay(100);
+
+ phost->device.speed = USBH_LL_GetSpeed(phost);
+
+ phost->gState = HOST_ENUMERATION;
+
+ phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00);
+ phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80);
+
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+
+ break;
+
+ case HOST_ENUMERATION:
+ /* Check for enumeration status */
+ if ( USBH_HandleEnum(phost) == USBH_OK)
+ {
+ /* The function shall return USBH_OK when full enumeration is complete */
+ USBH_UsrLog ("Enumeration done.");
+ phost->device.current_interface = 0;
+ if(phost->device.DevDesc.bNumConfigurations == 1)
+ {
+ USBH_UsrLog ("This device has only 1 configuration.");
+ phost->gState = HOST_SET_CONFIGURATION;
+
+ }
+ else
+ {
+ phost->gState = HOST_INPUT;
+ }
+
+ }
+ break;
+
+ case HOST_INPUT:
+ {
+ /* user callback for end of device basic enumeration */
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION);
+ phost->gState = HOST_SET_CONFIGURATION;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ }
+ break;
+
+ case HOST_SET_CONFIGURATION:
+ /* set configuration */
+ if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK)
+ {
+ phost->gState = HOST_CHECK_CLASS;
+ USBH_UsrLog ("Default configuration set.");
+
+ }
+
+ break;
+
+ case HOST_CHECK_CLASS:
+
+ if(phost->ClassNumber == 0)
+ {
+ USBH_UsrLog ("No Class has been registered.");
+ }
+ else
+ {
+ phost->pActiveClass = NULL;
+
+ for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++)
+ {
+ if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
+ {
+ phost->pActiveClass = phost->pClass[idx];
+ }
+ }
+
+ if(phost->pActiveClass != NULL)
+ {
+ if(phost->pActiveClass->Init(phost)== USBH_OK)
+ {
+ phost->gState = HOST_CLASS_REQUEST;
+ USBH_UsrLog ("%s class started.", phost->pActiveClass->Name);
+
+ /* Inform user that a class has been activated */
+ phost->pUser(phost, HOST_USER_CLASS_SELECTED);
+ }
+ else
+ {
+ phost->pUser(phost, HOST_USER_CLASS_FAILED);
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name);
+ }
+ }
+ else
+ {
+ phost->pUser(phost, HOST_USER_CLASS_FAILED);
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog ("No registered class for this device.");
+ }
+ }
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ break;
+
+ case HOST_CLASS_REQUEST:
+ /* process class standard control requests state machine */
+ if(phost->pActiveClass != NULL)
+ {
+ status = phost->pActiveClass->Requests(phost);
+
+ if(status == USBH_OK)
+ {
+ phost->gState = HOST_CLASS;
+ }
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_ErrLog ("Invalid Class Driver.");
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+
+ break;
+ case HOST_CLASS:
+ /* process class state machine */
+ if(phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->BgndProcess(phost);
+ }
+ break;
+
+ case HOST_DEV_DISCONNECTED:
+ USBH_Delay(USBH_DETACH_DELAY_MS);
+ DeInitStateMachine(phost);
+
+ /* Re-Initilaize Host for new Enumeration */
+ if(phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->DeInit(phost);
+ phost->pActiveClass = NULL;
+ }
+ break;
+
+ case HOST_ABORT_STATE:
+ default :
+ break;
+ }
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_HandleEnum
+ * This function includes the complete enumeration process
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+
+ switch (phost->EnumState)
+ {
+ case ENUM_IDLE:
+ /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
+ if ( USBH_Get_DevDesc(phost, 8) == USBH_OK)
+ {
+ phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
+
+ phost->EnumState = ENUM_GET_FULL_DEV_DESC;
+
+ /* modify control channels configuration for MaxPacket size */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ }
+ break;
+
+ case ENUM_GET_FULL_DEV_DESC:
+ /* Get FULL Device Desc */
+ if ( USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE)== USBH_OK)
+ {
+ USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct );
+ USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor );
+
+ phost->EnumState = ENUM_SET_ADDR;
+
+ }
+ break;
+
+ case ENUM_SET_ADDR:
+ /* set address */
+ if ( USBH_SetAddress(phost, USBH_DEVICE_ADDRESS) == USBH_OK)
+ {
+ USBH_Delay(2);
+ phost->device.address = USBH_DEVICE_ADDRESS;
+
+ /* user callback for device address assigned */
+ USBH_UsrLog("Address (#%d) assigned.", phost->device.address);
+ phost->EnumState = ENUM_GET_CFG_DESC;
+
+ /* modify control channels to update device address */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+ }
+ break;
+
+ case ENUM_GET_CFG_DESC:
+ /* get standard configuration descriptor */
+ if ( USBH_Get_CfgDesc(phost,
+ USB_CONFIGURATION_DESC_SIZE) == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_FULL_CFG_DESC;
+ }
+ break;
+
+ case ENUM_GET_FULL_CFG_DESC:
+ /* get FULL config descriptor (config, interface, endpoints) */
+ if (USBH_Get_CfgDesc(phost,
+ phost->device.CfgDesc.wTotalLength) == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_MFC_STRING_DESC;
+ }
+ break;
+
+ case ENUM_GET_MFC_STRING_DESC:
+ if (phost->device.DevDesc.iManufacturer != 0)
+ { /* Check that Manufacturer String is available */
+
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iManufacturer,
+ phost->device.Data ,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Manufacturing string */
+ USBH_UsrLog("Manufacturer : %s", (char *)phost->device.Data);
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Manufacturer : N/A");
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ case ENUM_GET_PRODUCT_STRING_DESC:
+ if (phost->device.DevDesc.iProduct != 0)
+ { /* Check that Product string is available */
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iProduct,
+ phost->device.Data,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Product string */
+ USBH_UsrLog("Product : %s", (char *)phost->device.Data);
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Product : N/A");
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ case ENUM_GET_SERIALNUM_STRING_DESC:
+ if (phost->device.DevDesc.iSerialNumber != 0)
+ { /* Check that Serial number string is available */
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iSerialNumber,
+ phost->device.Data,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Serial number string */
+ USBH_UsrLog("Serial Number : %s", (char *)phost->device.Data);
+ Status = USBH_OK;
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Serial Number : N/A");
+ Status = USBH_OK;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ default:
+ break;
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_LL_SetTimer
+ * Set the initial Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t time)
+{
+ phost->Timer = time;
+}
+/**
+ * @brief USBH_LL_IncTimer
+ * Increment Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_IncTimer (USBH_HandleTypeDef *phost)
+{
+ phost->Timer ++;
+ USBH_HandleSof(phost);
+}
+
+/**
+ * @brief USBH_HandleSof
+ * Call SOF process
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_HandleSof (USBH_HandleTypeDef *phost)
+{
+ if((phost->gState == HOST_CLASS)&&(phost->pActiveClass != NULL))
+ {
+ phost->pActiveClass->SOFProcess(phost);
+ }
+}
+/**
+ * @brief USBH_LL_Connect
+ * Handle USB Host connexion event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost)
+{
+ if(phost->gState == HOST_IDLE )
+ {
+ phost->device.is_connected = 1;
+
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_CONNECTION);
+ }
+ }
+ else if (phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT)
+ {
+ //On a cold boot with a low-speed device pre-attached,
+ //we get a second port-connected interrupt!???
+ //So go back and do the port reset again...
+ phost->gState = HOST_IDLE;
+ }
+ return USBH_OK;
+}
+
+
+
+USBH_StatusTypeDef USBH_LL_PortEnabled (USBH_HandleTypeDef *phost)
+{
+ if(phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT )
+ {
+ phost->gState = HOST_DEV_ATTACHED ;
+ }
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_LL_Disconnect
+ * Handle USB Host disconnection event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost)
+{
+ //Ignore false disconnect interrupt that sometimes intrudes
+ //while we are waiting for the port to enable :(
+ if (phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT)
+ {
+ return USBH_FAIL;
+ }
+
+ /*Stop Host */
+ USBH_LL_Stop(phost);
+
+ /* FRee Control Pipes */
+ USBH_FreePipe (phost, phost->Control.pipe_in);
+ USBH_FreePipe (phost, phost->Control.pipe_out);
+
+ phost->device.is_connected = 0;
+
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_DISCONNECTION);
+ }
+ USBH_UsrLog("USB Device disconnected");
+
+ /* Start the low level driver */
+ USBH_LL_Start(phost);
+
+ phost->gState = HOST_DEV_DISCONNECTED;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+
+ return USBH_OK;
+}
+
+
+#if (USBH_USE_OS == 1)
+/**
+ * @brief USB Host Thread task
+ * @param pvParameters not used
+ * @retval None
+ */
+static void USBH_Process_OS(void const * argument)
+{
+ osEvent event;
+
+ for(;;)
+ {
+ event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever );
+
+ if( event.status == osEventMessage )
+ {
+ USBH_Process((USBH_HandleTypeDef *)argument);
+ }
+ }
+}
+
+/**
+* @brief USBH_LL_NotifyURBChange
+* Notify URB state Change
+* @param phost: Host handle
+* @retval USBH Status
+*/
+USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost)
+{
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+ return USBH_OK;
+}
+#endif
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c
new file mode 100644
index 0000000..f9b8f6d
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c
@@ -0,0 +1,870 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements the control requests for device enumeration
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+* @brief This file implements the standard requests for device enumeration
+* @{
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+
+/** @defgroup USBH_CTLREQ_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_CTLREQ_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost);
+
+static void USBH_ParseDevDesc (USBH_DevDescTypeDef* , uint8_t *buf, uint16_t length);
+
+static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
+ uint8_t *buf,
+ uint16_t length);
+
+
+static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf);
+static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length);
+static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf);
+
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Functions
+* @{
+*/
+
+
+/**
+ * @brief USBH_Get_DevDesc
+ * Issue Get Device Descriptor command to the device. Once the response
+ * received, it parses the device descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint16_t length)
+{
+ USBH_StatusTypeDef status;
+
+ if (length > USBH_MAX_DATA_BUFFER)
+ {
+ length = USBH_MAX_DATA_BUFFER;
+ }
+
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_DEVICE,
+ 0,
+ phost->device.Data,
+ length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data, length);
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_Get_CfgDesc
+ * Issues Configuration Descriptor to the device. Once the response
+ * received, it parses the configuration descriptor and updates the
+ * status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
+ uint16_t length)
+
+{
+ USBH_StatusTypeDef status;
+ uint8_t *pData;
+
+#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
+ pData = phost->device.CfgDesc_Raw;
+
+ if (length > USBH_MAX_SIZE_CONFIGURATION)
+ {
+ length = USBH_MAX_SIZE_CONFIGURATION;
+ }
+#else
+ pData = phost->device.Data;
+
+ if (length > USBH_MAX_DATA_BUFFER)
+ {
+ length = USBH_MAX_DATA_BUFFER;
+ }
+#endif
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_CONFIGURATION,
+ 0,
+ pData,
+ length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseCfgDesc (&phost->device.CfgDesc,
+ pData,
+ length);
+
+ }
+ return status;
+}
+
+
+/**
+ * @brief USBH_Get_StringDesc
+ * Issues string Descriptor command to the device. Once the response
+ * received, it parses the string descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param string_index: String index for the descriptor
+ * @param buff: Buffer address for the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index,
+ uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+
+ if (length > USBH_MAX_DATA_BUFFER)
+ {
+ length = USBH_MAX_DATA_BUFFER;
+ }
+
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_STRING | string_index,
+ 0x0409,
+ phost->device.Data,
+ length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseStringDesc(phost->device.Data,buff, length);
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_GetDescriptor
+ * Issues Descriptor command to the device. Once the response received,
+ * it parses the descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param req_type: Descriptor type
+ * @param value_idx: Value for the GetDescriptr request
+ * @param buff: Buffer to store the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type,
+ uint16_t type_idx,
+ uint16_t value,
+ uint8_t* buff,
+ uint16_t length )
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
+ phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
+ phost->Control.setup.b.wValue.w = type_idx;
+ phost->Control.setup.b.wIndex.w = value;
+ phost->Control.setup.b.wLength.w = length;
+ }
+ return USBH_CtlReq(phost, buff , length );
+}
+
+/**
+ * @brief USBH_SetAddress
+ * This command sets the address to the connected device
+ * @param phost: Host Handle
+ * @param DeviceAddress: Device address to assign
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
+
+ phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_SetCfg
+ * The command sets the configuration value to the connected device
+ * @param phost: Host Handle
+ * @param cfg_idx: Configuration value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
+ uint16_t cfg_idx)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\
+ USB_REQ_TYPE_STANDARD;
+ phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
+ phost->Control.setup.b.wValue.w = cfg_idx;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_SetInterface
+ * The command sets the Interface value to the connected device
+ * @param phost: Host Handle
+ * @param altSetting: Interface value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
+ uint8_t ep_num, uint8_t altSetting)
+{
+
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE;
+ phost->Control.setup.b.wValue.w = altSetting;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_ClrFeature
+ * This request is used to clear or disable a specific feature.
+ * @param phost: Host Handle
+ * @param ep_num: endpoint number
+ * @param hc_num: Host channel number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
+ uint8_t ep_num)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_RECIPIENT_ENDPOINT |
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
+ phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_ParseDevDesc
+ * This function Parses the device descriptor
+ * @param dev_desc: device_descriptor destination address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseDevDesc (USBH_DevDescTypeDef* dev_desc,
+ uint8_t *buf,
+ uint16_t length)
+{
+ dev_desc->bLength = *(uint8_t *) (buf + 0);
+ dev_desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ dev_desc->bcdUSB = LE16 (buf + 2);
+ dev_desc->bDeviceClass = *(uint8_t *) (buf + 4);
+ dev_desc->bDeviceSubClass = *(uint8_t *) (buf + 5);
+ dev_desc->bDeviceProtocol = *(uint8_t *) (buf + 6);
+ dev_desc->bMaxPacketSize = *(uint8_t *) (buf + 7);
+
+ if (length > 8)
+ { /* For 1st time after device connection, Host may issue only 8 bytes for
+ Device Descriptor Length */
+ dev_desc->idVendor = LE16 (buf + 8);
+ dev_desc->idProduct = LE16 (buf + 10);
+ dev_desc->bcdDevice = LE16 (buf + 12);
+ dev_desc->iManufacturer = *(uint8_t *) (buf + 14);
+ dev_desc->iProduct = *(uint8_t *) (buf + 15);
+ dev_desc->iSerialNumber = *(uint8_t *) (buf + 16);
+ dev_desc->bNumConfigurations = *(uint8_t *) (buf + 17);
+ }
+}
+
+/**
+ * @brief USBH_ParseCfgDesc
+ * This function Parses the configuration descriptor
+ * @param cfg_desc: Configuration Descriptor address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
+ uint8_t *buf,
+ uint16_t length)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_EpDescTypeDef *pep;
+ USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf;
+ uint16_t ptr;
+ int8_t if_ix = 0;
+ int8_t ep_ix = 0;
+
+ pdesc = (USBH_DescHeader_t *)buf;
+
+ /* Parse configuration descriptor */
+ cfg_desc->bLength = *(uint8_t *) (buf + 0);
+ cfg_desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ cfg_desc->wTotalLength = LE16 (buf + 2);
+ cfg_desc->bNumInterfaces = *(uint8_t *) (buf + 4);
+ cfg_desc->bConfigurationValue = *(uint8_t *) (buf + 5);
+ cfg_desc->iConfiguration = *(uint8_t *) (buf + 6);
+ cfg_desc->bmAttributes = *(uint8_t *) (buf + 7);
+ cfg_desc->bMaxPower = *(uint8_t *) (buf + 8);
+
+
+ if (length > USB_CONFIGURATION_DESC_SIZE)
+ {
+ ptr = USB_LEN_CFG_DESC;
+ pif = (USBH_InterfaceDescTypeDef *)0;
+
+ //***************
+ //Todo: This does not check for malformed descriptors. Needs hardening!
+ //***************
+ while ((if_ix < USBH_MAX_NUM_INTERFACES ) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
+ {
+ pif = &cfg_desc->Itf_Desc[if_ix];
+ USBH_ParseInterfaceDesc (pif, (uint8_t *)pdesc);
+
+ ep_ix = 0;
+ pep = (USBH_EpDescTypeDef *)0;
+ while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((uint8_t*) pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
+ {
+ pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
+ USBH_ParseEPDesc (pep, (uint8_t *)pdesc);
+ ep_ix++;
+ }
+ }
+ if_ix++;
+ }
+ }
+ }
+}
+
+
+
+/**
+ * @brief USBH_ParseInterfaceDesc
+ * This function Parses the interface descriptor
+ * @param if_descriptor : Interface descriptor destination
+ * @param buf: Buffer where the descriptor data is available
+ * @retval None
+ */
+static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor,
+ uint8_t *buf)
+{
+ if_descriptor->bLength = *(uint8_t *) (buf + 0);
+ if_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
+ if_descriptor->bInterfaceNumber = *(uint8_t *) (buf + 2);
+ if_descriptor->bAlternateSetting = *(uint8_t *) (buf + 3);
+ if_descriptor->bNumEndpoints = *(uint8_t *) (buf + 4);
+ if_descriptor->bInterfaceClass = *(uint8_t *) (buf + 5);
+ if_descriptor->bInterfaceSubClass = *(uint8_t *) (buf + 6);
+ if_descriptor->bInterfaceProtocol = *(uint8_t *) (buf + 7);
+ if_descriptor->iInterface = *(uint8_t *) (buf + 8);
+}
+
+/**
+ * @brief USBH_ParseEPDesc
+ * This function Parses the endpoint descriptor
+ * @param ep_descriptor: Endpoint descriptor destination address
+ * @param buf: Buffer where the parsed descriptor stored
+ * @retval None
+ */
+static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor,
+ uint8_t *buf)
+{
+
+ ep_descriptor->bLength = *(uint8_t *) (buf + 0);
+ ep_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
+ ep_descriptor->bEndpointAddress = *(uint8_t *) (buf + 2);
+ ep_descriptor->bmAttributes = *(uint8_t *) (buf + 3);
+ ep_descriptor->wMaxPacketSize = LE16 (buf + 4);
+ ep_descriptor->bInterval = *(uint8_t *) (buf + 6);
+}
+
+/**
+ * @brief USBH_ParseStringDesc
+ * This function Parses the string descriptor
+ * @param psrc: Source pointer containing the descriptor data
+ * @param pdest: Destination address pointer
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseStringDesc (uint8_t* psrc,
+ uint8_t* pdest,
+ uint16_t length)
+{
+ uint16_t strlength;
+ uint16_t idx;
+
+ /* The UNICODE string descriptor is not NULL-terminated. The string length is
+ computed by substracting two from the value of the first byte of the descriptor.
+ */
+
+ /* Check which is lower size, the Size of string or the length of bytes read
+ from the device */
+
+ if ( psrc[1] == USB_DESC_TYPE_STRING)
+ { /* Make sure the Descriptor is String Type */
+
+ /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
+ strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length);
+ psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */
+
+ for (idx = 0; idx < strlength; idx+=2 )
+ {/* Copy Only the string and ignore the UNICODE ID, hence add the src */
+ *pdest = psrc[idx];
+ pdest++;
+ }
+ *pdest = 0; /* mark end of string */
+ }
+}
+
+/**
+ * @brief USBH_GetNextDesc
+ * This function return the next descriptor header
+ * @param buf: Buffer where the cfg descriptor is available
+ * @param ptr: data pointer inside the cfg descriptor
+ * @retval next header
+ */
+USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, uint16_t *ptr)
+{
+ USBH_DescHeader_t *pnext;
+
+ *ptr += ((USBH_DescHeader_t *)pbuf)->bLength;
+ pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \
+ ((USBH_DescHeader_t *)pbuf)->bLength);
+
+ return(pnext);
+}
+
+
+/**
+ * @brief USBH_CtlReq
+ * USBH_CtlReq sends a control request and provide the status after
+ * completion of the request
+ * @param phost: Host Handle
+ * @param req: Setup Request Structure
+ * @param buff: data buffer address to store the response
+ * @param length: length of the response
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+ status = USBH_BUSY;
+
+ switch (phost->RequestState)
+ {
+ case CMD_SEND:
+ /* Start a SETUP transfer */
+ phost->Control.buff = buff;
+ phost->Control.length = length;
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_WAIT;
+ status = USBH_BUSY;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ break;
+
+ case CMD_WAIT:
+ status = USBH_HandleControl(phost);
+ if (status != USBH_BUSY)
+ {
+ phost->RequestState = CMD_SEND;
+ phost->Control.state = CTRL_IDLE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_HandleControl
+ * Handles the USB control transfer state machine
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
+{
+ uint8_t direction;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+
+ switch (phost->Control.state)
+ {
+ case CTRL_SETUP:
+ /* send a SETUP packet */
+ phost->Control.timer = phost->Timer;
+ USBH_CtlSendSetup(phost,
+ (uint8_t *)phost->Control.setup.d8 ,
+ phost->Control.pipe_out);
+ phost->Control.state = CTRL_SETUP_WAIT;
+ break;
+
+ case CTRL_SETUP_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+ /* case SETUP packet sent successfully */
+ if(URB_Status == USBH_URB_DONE)
+ {
+ direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
+
+ /* check if there is a data stage */
+ if (phost->Control.setup.b.wLength.w != 0 )
+ {
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_DATA_OUT;
+ }
+ }
+ /* No DATA stage */
+ else
+ {
+ /* If there is No Data Transfer Stage */
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_STATUS_OUT;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_STATUS_IN;
+ }
+ }
+ }
+ else if(URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ //Some mice cause a transaction error interrupt (HCINT_TXERR) at this point.
+ //Other mice just NAK our transaction.
+ //Either way we need to retry, but keep our original timeout so we don't wait forever.
+ USBH_CtlSendSetup(phost,
+ (uint8_t *)phost->Control.setup.d8 ,
+ phost->Control.pipe_out);
+ }
+
+ if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ break;
+
+ case CTRL_DATA_IN:
+ /* Issue an IN token */
+ phost->Control.timer = phost->Timer;
+ USBH_CtlReceiveData(phost,
+ phost->Control.buff,
+ phost->Control.length,
+ phost->Control.pipe_in);
+
+ phost->Control.state = CTRL_DATA_IN_WAIT;
+ break;
+
+ case CTRL_DATA_IN_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
+
+ /* check is DATA packet transferred successfully */
+ if (URB_Status == USBH_URB_DONE)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+ }
+
+ /* manage error cases*/
+ if (URB_Status == USBH_URB_STALL)
+ {
+ //Command not supported, report to callee
+ status = USBH_NOT_SUPPORTED;
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ /* Device error */
+ phost->Control.state = CTRL_ERROR;
+ }
+
+ if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ break;
+
+ case CTRL_DATA_OUT:
+ phost->Control.timer = phost->Timer;
+ USBH_CtlSendData (phost,
+ phost->Control.buff,
+ phost->Control.length ,
+ phost->Control.pipe_out,
+ 1);
+ phost->Control.state = CTRL_DATA_OUT_WAIT;
+ break;
+
+ case CTRL_DATA_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+
+ if (URB_Status == USBH_URB_DONE)
+ { /* If the Setup Pkt is sent successful, then change the state */
+ phost->Control.state = CTRL_STATUS_IN;
+ }
+
+ /* handle error cases */
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ //Command not supported, report to callee
+ status = USBH_NOT_SUPPORTED;
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Nack received from device */
+ phost->Control.state = CTRL_DATA_OUT;
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ /* device error */
+ phost->Control.state = CTRL_ERROR;
+ status = USBH_FAIL;
+ }
+
+ if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ break;
+
+
+ case CTRL_STATUS_IN:
+ /* Send 0 bytes out packet */
+ phost->Control.timer = phost->Timer;
+ USBH_CtlReceiveData (phost,
+ 0,
+ 0,
+ phost->Control.pipe_in);
+ phost->Control.state = CTRL_STATUS_IN_WAIT;
+ break;
+
+ case CTRL_STATUS_IN_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
+
+ if ( URB_Status == USBH_URB_DONE)
+ { /* Control transfers completed, Exit the State Machine */
+ phost->Control.state = CTRL_COMPLETE;
+ status = USBH_OK;
+ }
+
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ //Command not supported, report to callee
+ status = USBH_NOT_SUPPORTED;
+ }
+
+ if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ break;
+
+ case CTRL_STATUS_OUT:
+ phost->Control.timer = phost->Timer;
+ USBH_CtlSendData (phost,
+ 0,
+ 0,
+ phost->Control.pipe_out,
+ 1);
+ phost->Control.state = CTRL_STATUS_OUT_WAIT;
+ break;
+
+ case CTRL_STATUS_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
+ if (URB_Status == USBH_URB_DONE)
+ {
+ status = USBH_OK;
+ phost->Control.state = CTRL_COMPLETE;
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+
+ if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
+ {
+ phost->Control.state = CTRL_ERROR;
+ }
+ break;
+
+ case CTRL_ERROR:
+ /*
+ After a halt condition is encountered or an error is detected by the
+ host, a control endpoint is allowed to recover by accepting the next Setup
+ PID; i.e., recovery actions via some other pipe are not required for control
+ endpoints. For the Default Control Pipe, a device reset will ultimately be
+ required to clear the halt or error condition if the next Setup PID is not
+ accepted.
+ */
+ if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
+ {
+ /* try to recover control */
+// USBH_LL_Stop(phost);
+
+ /* Do the transmission again, starting from SETUP Packet */
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_SEND;
+ }
+ else
+ {
+ phost->pUser(phost, HOST_USER_UNRECOVERED_ERROR);
+ phost->Control.errorcount = 0;
+ USBH_ErrLog("Control error");
+ status = USBH_FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ioreq.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ioreq.c
new file mode 100644
index 0000000..e67787c
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ioreq.c
@@ -0,0 +1,358 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file handles the issuing of the USB transactions
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+/* Includes ------------------------------------------------------------------*/
+
+#include "usbh_ioreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file handles the standard protocol processing (USB v2.0)
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_IOREQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+/** @defgroup USBH_IOREQ_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Functions
+ * @{
+ */
+
+
+
+/**
+ * @brief USBH_CtlSendSetup
+ * Sends the Setup Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be send to Device
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t pipe_num)
+{
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_SETUP, /* Type setup */
+ buff, /* data buffer */
+ USBH_SETUP_PKT_SIZE, /* data length */
+ 0);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlSendData
+ * Sends a data Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping )
+{
+ if(phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0;
+ }
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlReceiveData
+ * Receives the Device Response to the Setup Packet
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t* buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+ return USBH_OK;
+
+}
+
+
+/**
+ * @brief USBH_BulkSendData
+ * Sends the Bulk Packet to the device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping )
+{
+ if(phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0;
+ }
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_BulkReceiveData
+ * Receives IN bulk packet from device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the received data packet to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_InterruptReceiveData
+ * Receives the Device Response to the Interrupt IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_InterruptSendData
+ * Sends the data on Interrupt OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocReceiveData
+ * Receives the Device Response to the Isochronous IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocSendData
+ * Sends the data on Isochronous OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c
new file mode 100644
index 0000000..97048de
--- /dev/null
+++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c
@@ -0,0 +1,205 @@
+/**
+ ******************************************************************************
+ * @file usbh_pipes.c
+ * @author MCD Application Team
+ * @version V3.2.1
+ * @date 26-June-2015
+ * @brief This file implements functions for opening and closing Pipes
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2015 STMicroelectronics
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_pipes.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file includes opening and closing Pipes
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Functions
+ * @{
+ */
+static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost);
+
+
+/**
+ * @brief USBH_Open_Pipe
+ * Open a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @param dev_address: USB Device address allocated to attached device
+ * @param speed : USB device speed (Full/Low)
+ * @param ep_type: end point type (Bulk/int/ctl)
+ * @param mps: max pkt size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+
+ USBH_LL_OpenPipe(phost,
+ pipe_num,
+ epnum,
+ dev_address,
+ speed,
+ ep_type,
+ mps);
+
+ return USBH_OK;
+
+}
+
+/**
+ * @brief USBH_ClosePipe
+ * Close a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num)
+{
+
+ USBH_LL_ClosePipe(phost, pipe_num);
+
+ return USBH_OK;
+
+}
+
+/**
+ * @brief USBH_Alloc_Pipe
+ * Allocate a new Pipe
+ * @param phost: Host Handle
+ * @param ep_addr: End point for which the Pipe to be allocated
+ * @retval Pipe number
+ */
+uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost, uint8_t ep_addr)
+{
+ uint16_t pipe;
+
+ pipe = USBH_GetFreePipe(phost);
+
+ if (pipe != 0xFFFF)
+ {
+ phost->Pipes[pipe] = 0x8000 | ep_addr;
+ }
+ return pipe;
+}
+
+/**
+ * @brief USBH_Free_Pipe
+ * Free the USB Pipe
+ * @param phost: Host Handle
+ * @param idx: Pipe number to be freed
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost, uint8_t idx)
+{
+ if (idx < HOST_PIPE_COUNT)
+ {
+ phost->Pipes[idx] &= 0x7FFF;
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_GetFreePipe
+ * @param phost: Host Handle
+ * Get a free Pipe number for allocation to a device endpoint
+ * @retval idx: Free Pipe number
+ */
+static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost)
+{
+ uint8_t idx = 0;
+
+ //We need to limit allocated pipes to the number actually provided by hardware!
+ for (idx = 0 ; idx < ((HCD_HandleTypeDef*)phost->pData)->Init.Host_channels; idx++)
+ {
+ if ((phost->Pipes[idx] & 0x8000) == 0)
+ {
+ return idx;
+ }
+ }
+ return 0xFFFF;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Downstream/Src/downstream_hid.c b/Downstream/Src/downstream_hid.c
new file mode 100644
index 0000000..a366f6f
--- /dev/null
+++ b/Downstream/Src/downstream_hid.c
@@ -0,0 +1,451 @@
+/*
+ * downstream_hid.c
+ *
+ * Created on: Apr 10, 2016
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+
+#include "downstream_hid.h"
+#include "downstream_statemachine.h"
+#include "usbh_hid.h"
+#include "stm32f4xx_hal.h"
+#include "build_config.h"
+
+
+#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+
+extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c
+extern InterfaceCommandClassTypeDef ConfiguredDeviceClass; //Do a cheap hard-link to downstream_statemachine.c, rather than keep a duplicate here
+
+
+//Information required to extract the data we need from incoming device reports.
+uint8_t ReportButtonBitOffset;
+uint8_t ReportButtonBitLength;
+uint8_t ReportXBitOffset;
+uint8_t ReportXBitLength;
+uint8_t ReportYBitOffset;
+uint8_t ReportYBitLength;
+uint8_t ReportWheelBitOffset;
+uint8_t ReportWheelBitLength;
+
+//Stuff used while parsing HID report
+uint8_t* ReportDataPointer;
+uint8_t ItemHeader;
+uint8_t ItemData;
+
+
+
+static HAL_StatusTypeDef Downstream_HID_Mouse_ParseReportDescriptor(void);
+static HAL_StatusTypeDef Downstream_HID_GetNextReportItem(void);
+static void Downstream_HID_Mouse_ExtractDataFromReport(DownstreamPacketTypeDef* packetToSend);
+static void Downstream_HID_Keyboard_ExtractDataFromReport(DownstreamPacketTypeDef* packetToSend);
+static uint8_t Downstream_HID_Mouse_Extract8BitValue(HID_HandleTypeDef* hidHandle,
+ uint8_t valueBitOffset,
+ uint8_t valueBitLength);
+
+
+InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void)
+{
+ HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+#ifdef CONFIG_MOUSE_ENABLED
+ if (HID_Handle->Protocol == HID_MOUSE_PROTOCOL)
+ {
+ if (Downstream_HID_Mouse_ParseReportDescriptor() == HAL_OK)
+ {
+ return COMMAND_CLASS_HID_MOUSE; //success!
+ }
+ }
+#endif
+#ifdef CONFIG_KEYBOARD_ENABLED
+ if (HID_Handle->Protocol == HID_KEYBRD_PROTOCOL)
+ {
+ return COMMAND_CLASS_HID_KEYBOARD; //success!
+ }
+#endif
+
+ //else:
+ return COMMAND_CLASS_INTERFACE; //fail
+}
+
+
+#ifdef CONFIG_MOUSE_ENABLED
+static HAL_StatusTypeDef Downstream_HID_Mouse_ParseReportDescriptor(void)
+{
+ uint32_t currentReportBitIndex = 0;
+ uint8_t currentUsagePage = 0;
+ uint8_t currentUsageIndex = 0;
+ uint8_t xUsageIndex = 0xFF;
+ uint8_t yUsageIndex = 0xFF;
+ uint8_t wheelUsageIndex = 0xFF;
+ uint8_t currentReportSize = 0;
+ uint8_t currentReportCount = 0;
+
+ ReportDataPointer = hUsbHostFS.device.Data;
+
+ ReportButtonBitLength = 0;
+ ReportXBitLength = 0;
+ ReportYBitLength = 0;
+ ReportWheelBitLength = 0;
+
+ while ((Downstream_HID_GetNextReportItem() == HAL_OK) && ((ReportButtonBitLength == 0) ||
+ (ReportXBitLength == 0) ||
+ (ReportYBitLength == 0) ||
+ (ReportWheelBitLength == 0)))
+ {
+ switch (ItemHeader)
+ {
+ case HID_ITEM_USAGE_PAGE:
+ currentUsagePage = ItemData;
+ currentUsageIndex = 0;
+ xUsageIndex = 0xFF;
+ yUsageIndex = 0xFF;
+ wheelUsageIndex = 0xFF;
+ break;
+
+ case HID_ITEM_COLLECTION: //Physical collections also clear the usage index...
+ if (ItemData == HID_ITEM_COLLECTION_PHYS)
+ {
+ currentUsageIndex = 0;
+ xUsageIndex = 0xFF;
+ yUsageIndex = 0xFF;
+ wheelUsageIndex = 0xFF;
+ }
+ break;
+
+ case HID_ITEM_END_COLLECTION: //...and so do collection ends
+ currentUsageIndex = 0;
+ xUsageIndex = 0xFF;
+ yUsageIndex = 0xFF;
+ wheelUsageIndex = 0xFF;
+ break;
+
+ case HID_ITEM_USAGE:
+ switch (ItemData)
+ {
+ case HID_ITEM_USAGE_X:
+ xUsageIndex = currentUsageIndex;
+ break;
+
+ case HID_ITEM_USAGE_Y:
+ yUsageIndex = currentUsageIndex;
+ break;
+
+ case HID_ITEM_USAGE_WHEEL:
+ wheelUsageIndex = currentUsageIndex;
+ break;
+ }
+ currentUsageIndex++;
+ break;
+
+ case HID_ITEM_REPORT_SIZE:
+ currentReportSize = ItemData;
+ break;
+
+ case HID_ITEM_REPORT_COUNT:
+ currentReportCount = ItemData;
+ break;
+
+ case HID_ITEM_REPORT_ID:
+ currentReportBitIndex += 8; //Rudimentary support for a single report ID
+ break;
+
+ case HID_ITEM_INPUT:
+ switch (currentUsagePage)
+ {
+ case HID_ITEM_USAGE_PAGE_BUTTON:
+ if (ItemData == HID_ITEM_INPUT_ABS)
+ {
+ //Buttons found!
+ if (currentReportSize != 1)
+ {
+ return HAL_ERROR;
+ }
+ ReportButtonBitOffset = currentReportBitIndex;
+ ReportButtonBitLength = currentReportCount;
+ if (ReportButtonBitLength > HID_MOUSE_MAX_BUTTONS)
+ {
+ ReportButtonBitLength = HID_MOUSE_MAX_BUTTONS;
+ }
+ }
+ break;
+
+ case HID_ITEM_USAGE_PAGE_DESKTOP:
+ if (ItemData == HID_ITEM_INPUT_REL)
+ {
+ //Movement data found!
+ if ((currentReportSize < 8) || (currentReportSize > 16))
+ {
+ return HAL_ERROR;
+ }
+ if (xUsageIndex != 0xFF)
+ {
+ ReportXBitOffset = currentReportBitIndex + (currentReportSize * xUsageIndex);
+ ReportXBitLength = currentReportSize;
+ if ((ReportXBitOffset + ReportXBitLength) > (HID_MAX_REPORT_LEN * 8))
+ {
+ return HAL_ERROR;
+ }
+ }
+ if (yUsageIndex != 0xFF)
+ {
+ ReportYBitOffset = currentReportBitIndex + (currentReportSize * yUsageIndex);
+ ReportYBitLength = currentReportSize;
+ if ((ReportYBitOffset + ReportYBitLength) > (HID_MAX_REPORT_LEN * 8))
+ {
+ return HAL_ERROR;
+ }
+ }
+ if (wheelUsageIndex != 0xFF)
+ {
+ ReportWheelBitOffset = currentReportBitIndex + (currentReportSize * wheelUsageIndex);
+ ReportWheelBitLength = currentReportSize;
+ if ((ReportWheelBitOffset + ReportWheelBitLength) > (HID_MAX_REPORT_LEN * 8))
+ {
+ return HAL_ERROR;
+ }
+ }
+ }
+ break;
+ }
+ currentUsageIndex = 0;
+ xUsageIndex = 0xFF;
+ yUsageIndex = 0xFF;
+ wheelUsageIndex = 0xFF;
+ currentReportBitIndex += (currentReportSize * currentReportCount);
+ break;
+ }
+ }
+
+ //We don't mind if we didn't find a scrollwheel item.
+ if ((ReportButtonBitLength == 0) ||
+ (ReportXBitLength == 0) ||
+ (ReportYBitLength == 0))
+ {
+ return HAL_ERROR;
+ }
+
+ return HAL_OK;
+}
+
+
+//Retrieves the next item in the HID report, and at most one of its associated data bytes.
+//Then it updates ReportDataPointer based on the actual length of the retrieved item.
+static HAL_StatusTypeDef Downstream_HID_GetNextReportItem(void)
+{
+ HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+ uint32_t itemLength;
+
+ if ((ReportDataPointer >= &hUsbHostFS.device.Data[USBH_MAX_DATA_BUFFER]) ||
+ ((ReportDataPointer - &hUsbHostFS.device.Data[0]) >= HID_Handle->HID_Desc.wItemLength))
+ {
+ return HAL_ERROR;
+ }
+
+ ItemHeader = *ReportDataPointer & HID_ITEM_MASK;
+ itemLength = *ReportDataPointer & HID_ITEM_LENGTH_MASK;
+ ReportDataPointer++;
+
+ if (itemLength == 3)
+ {
+ itemLength = 4; //Length = 3 actually means 4 bytes
+ }
+
+ if (ItemHeader == HID_ITEM_LONG)
+ {
+ itemLength += *ReportDataPointer; //Long items have another length byte
+ }
+ else
+ {
+ if (itemLength > 0)
+ {
+ ItemData = *ReportDataPointer; //If it is a short item, grab its first data byte
+ }
+ }
+
+ ReportDataPointer += itemLength;
+ return HAL_OK;
+}
+#endif //#ifdef CONFIG_MOUSE_ENABLED
+
+
+
+void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
+{
+ if (receivedPacket->Command == COMMAND_HID_GET_REPORT)
+ {
+ Downstream_ReleasePacket(receivedPacket);
+ if (USBH_HID_GetInterruptReport(&hUsbHostFS,
+ Downstream_HID_InterruptReportCallback) != HAL_OK)
+ {
+ Downstream_PacketProcessor_FreakOut();
+ }
+ Downstream_PacketProcessor_NotifyDisconnectReplyRequired();
+ return;
+ }
+
+#ifdef CONFIG_KEYBOARD_ENABLED
+ if (receivedPacket->Command == COMMAND_HID_SET_REPORT)
+ {
+ if ((ConfiguredDeviceClass != COMMAND_CLASS_HID_KEYBOARD) ||
+ (receivedPacket->Length16 != ((HID_KEYBOARD_OUTPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16) ||
+ ((receivedPacket->Data[0] & ~((1 << HID_KEYBOARD_MAX_LED) - 1)) != 0))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ }
+ USBH_HID_SetReport(&hUsbHostFS,
+ HID_REPORT_DIRECTION_OUT,
+ 0,
+ receivedPacket->Data,
+ HID_KEYBOARD_OUTPUT_DATA_LEN,
+ Downstream_HID_SendReportCallback);
+ Downstream_ReleasePacket(receivedPacket);
+ Downstream_PacketProcessor_NotifyDisconnectReplyRequired();
+ return;
+ }
+#endif //#ifdef CONFIG_KEYBOARD_ENABLED
+
+ //else:
+ Downstream_PacketProcessor_FreakOut();
+}
+
+
+void Downstream_HID_InterruptReportCallback(USBH_StatusTypeDef result)
+{
+ DownstreamPacketTypeDef* freePacket;
+
+ freePacket = Downstream_GetFreePacketImmediately();
+
+ if (result == USBH_OK)
+ {
+ //Data received from device
+#ifdef CONFIG_MOUSE_ENABLED
+ if (ConfiguredDeviceClass == COMMAND_CLASS_HID_MOUSE)
+ {
+ Downstream_HID_Mouse_ExtractDataFromReport(freePacket);
+ freePacket->Length16 = ((HID_MOUSE_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16;
+ }
+ else
+#endif
+#ifdef CONFIG_KEYBOARD_ENABLED
+ if (ConfiguredDeviceClass == COMMAND_CLASS_HID_KEYBOARD)
+ {
+ Downstream_HID_Keyboard_ExtractDataFromReport(freePacket);
+ freePacket->Length16 = ((HID_KEYBOARD_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16;
+ }
+ else
+#endif
+
+ //else if...
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+ }
+ else
+ {
+ //NAK received from device, return zero-length packet
+ freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
+ }
+
+ freePacket->CommandClass = ConfiguredDeviceClass;
+ freePacket->Command = COMMAND_HID_GET_REPORT;
+ Downstream_PacketProcessor_ClassReply(freePacket);
+}
+
+
+#ifdef CONFIG_MOUSE_ENABLED
+static void Downstream_HID_Mouse_ExtractDataFromReport(DownstreamPacketTypeDef* packetToSend)
+{
+ HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+ uint32_t readData;
+
+ readData = *(uint32_t*)&(HID_Handle->Data[(ReportButtonBitOffset / 8)]);
+ readData >>= (ReportButtonBitOffset % 8);
+ readData &= ((1 << ReportButtonBitLength) - 1); //Truncate extra buttons
+ packetToSend->Data[0] = readData;
+
+ packetToSend->Data[1] = Downstream_HID_Mouse_Extract8BitValue(HID_Handle,
+ ReportXBitOffset,
+ ReportXBitLength);
+
+ packetToSend->Data[2] = Downstream_HID_Mouse_Extract8BitValue(HID_Handle,
+ ReportYBitOffset,
+ ReportYBitLength);
+
+ packetToSend->Data[3] = Downstream_HID_Mouse_Extract8BitValue(HID_Handle,
+ ReportWheelBitOffset,
+ ReportWheelBitLength);
+}
+
+
+
+static uint8_t Downstream_HID_Mouse_Extract8BitValue(HID_HandleTypeDef* hidHandle,
+ uint8_t valueBitOffset,
+ uint8_t valueBitLength)
+{
+ int32_t readData;
+
+ readData = *(uint32_t*)&(hidHandle->Data[(valueBitOffset / 8)]);
+ readData >>= (valueBitOffset % 8);
+ if (readData & (1 << (valueBitLength - 1))) //If value is negative...
+ {
+ readData |= ~((1 << valueBitLength) - 1); //...sign-extend to full width...
+ }
+ else
+ {
+ readData &= (1 << valueBitLength) - 1; //...else zero out unwanted bits
+ }
+ if (readData < INT8_MIN) readData = INT8_MIN; //Limit to 8-bit values
+ if (readData > INT8_MAX) readData = INT8_MAX;
+ return (int8_t)readData;
+}
+#endif //#ifdef CONFIG_MOUSE_ENABLED
+
+
+#ifdef CONFIG_KEYBOARD_ENABLED
+static void Downstream_HID_Keyboard_ExtractDataFromReport(DownstreamPacketTypeDef* packetToSend)
+{
+ HID_HandleTypeDef* HID_Handle = (HID_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+ uint32_t i;
+ uint8_t readData;
+
+ packetToSend->Data[0] = HID_Handle->Data[0]; //Modifier keys - pass straight through
+ packetToSend->Data[1] = 0; //Constant byte
+
+ for (i = 2; i < HID_KEYBOARD_INPUT_DATA_LEN; i++) //Key array
+ {
+ readData = HID_Handle->Data[i];
+ if (readData > HID_KEYBOARD_MAX_KEY)
+ {
+ readData = HID_KEYBOARD_MAX_KEY;
+ }
+ packetToSend->Data[i] = readData;
+ }
+}
+#endif //#ifdef CONFIG_KEYBOARD_ENABLED
+
+
+
+void Downstream_HID_SendReportCallback(USBH_StatusTypeDef result)
+{
+ UNUSED(result);
+
+ DownstreamPacketTypeDef* freePacket;
+
+ freePacket = Downstream_GetFreePacketImmediately();
+ freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
+ freePacket->CommandClass = ConfiguredDeviceClass;
+ freePacket->Command = COMMAND_HID_SET_REPORT;
+ Downstream_PacketProcessor_ClassReply(freePacket);
+}
+
+
+#endif //#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+
diff --git a/Downstream/Src/downstream_msc.c b/Downstream/Src/downstream_msc.c
new file mode 100644
index 0000000..7111ce9
--- /dev/null
+++ b/Downstream/Src/downstream_msc.c
@@ -0,0 +1,358 @@
+/*
+ * downstream_msc.c
+ *
+ * Created on: 8/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+#include "downstream_msc.h"
+#include "downstream_interface_def.h"
+#include "downstream_statemachine.h"
+#include "downstream_spi.h"
+#include "usbh_msc.h"
+#include "build_config.h"
+#include "led.h"
+
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+
+extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c
+
+
+//Stuff we need to save for our callbacks to use:
+DownstreamMSCCallbackPacketTypeDef GetStreamDataCallback;
+uint32_t ByteCount;
+DownstreamPacketTypeDef* ReadStreamPacket;
+uint8_t ReadStreamBusy;
+
+
+static void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_StatusTypeDef result);
+static void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_BeginWrite(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_RdWrCompleteCallback(USBH_StatusTypeDef result);
+static void Downstream_MSC_GetStreamDataPacketCallback(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_Disconnect(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_MSC_PacketProcessor_DisconnectCallback(USBH_StatusTypeDef result);
+
+
+//High-level checks on the connected device. We don't want some weirdly
+//configured device to bomb our USB stack, accidentally or otherwise.
+InterfaceCommandClassTypeDef Downstream_MSC_ApproveConnectedDevice(void)
+{
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ if (MSC_Handle->unit[MSC_FIXED_LUN].error != MSC_OK)
+ {
+ return COMMAND_CLASS_INTERFACE; //fail
+ }
+
+ if ((MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr == 0) ||
+ (MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr == UINT32_MAX))
+ {
+ return COMMAND_CLASS_INTERFACE; //fail
+ }
+
+ if (MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size != MSC_SUPPORTED_BLOCK_SIZE)
+ {
+ return COMMAND_CLASS_INTERFACE; //fail
+ }
+
+ return COMMAND_CLASS_MASS_STORAGE; //success!
+}
+
+
+void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
+{
+ switch (receivedPacket->Command)
+ {
+ case COMMAND_MSC_TEST_UNIT_READY:
+ Downstream_MSC_PacketProcessor_TestUnitReady(receivedPacket);
+ break;
+
+ case COMMAND_MSC_GET_CAPACITY:
+ Downstream_MSC_PacketProcessor_GetCapacity(receivedPacket);
+ break;
+
+ case COMMAND_MSC_READ:
+ Downstream_MSC_PacketProcessor_BeginRead(receivedPacket);
+ break;
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+ case COMMAND_MSC_WRITE:
+ Downstream_MSC_PacketProcessor_BeginWrite(receivedPacket);
+ break;
+#endif
+
+ case COMMAND_MSC_DISCONNECT:
+ Downstream_MSC_PacketProcessor_Disconnect(receivedPacket);
+ break;
+
+ case COMMAND_MSC_POLL_DISCONNECT:
+ Downstream_PacketProcessor_ClassReply(receivedPacket); //Device is still connected, so send the packet straight back
+ break;
+
+ default:
+ Downstream_PacketProcessor_FreakOut();
+ }
+
+}
+
+
+static void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket)
+{
+ Downstream_ReleasePacket(receivedPacket);
+
+ if (USBH_MSC_UnitIsReady(&hUsbHostFS,
+ MSC_FIXED_LUN,
+ Downstream_MSC_PacketProcessor_TestUnitReadyCallback) != USBH_BUSY)
+ {
+ Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_FAIL);
+ }
+}
+
+
+static void Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_StatusTypeDef result)
+{
+ DownstreamPacketTypeDef* freePacket;
+
+ freePacket = Downstream_GetFreePacketImmediately();
+ freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
+ freePacket->Command = COMMAND_MSC_TEST_UNIT_READY;
+ freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
+
+ if (result == USBH_OK)
+ {
+ freePacket->Data[0] = HAL_OK;
+ }
+ else
+ {
+ freePacket->Data[0] = HAL_ERROR;
+ }
+ Downstream_PacketProcessor_ClassReply(freePacket);
+}
+
+
+
+static void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket)
+{
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + (8 / 2);
+ *(uint32_t*)&(receivedPacket->Data[0]) = MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr;
+ *(uint32_t*)&(receivedPacket->Data[4]) = (uint32_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
+ Downstream_PacketProcessor_ClassReply(receivedPacket);
+}
+
+
+
+static void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket)
+{
+ uint64_t readBlockAddress;
+ uint32_t readBlockCount;
+ uint64_t readByteCount;
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ if (receivedPacket->Length16 != (DOWNSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2)))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ LED_SetState(LED_STATUS_FLASH_READWRITE);
+ readBlockAddress = *(uint64_t*)&(receivedPacket->Data[0]);
+ readBlockCount = *(uint32_t*)&(receivedPacket->Data[8]);
+ readByteCount = readBlockCount * MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
+ if ((readBlockAddress >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
+ ((readBlockAddress + readBlockCount - 1) >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
+ (readByteCount > UINT32_MAX))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ receivedPacket->Data[0] = HAL_ERROR;
+ receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
+ if (USBH_MSC_Read(&hUsbHostFS,
+ MSC_FIXED_LUN,
+ (uint32_t)readBlockAddress,
+ readBlockCount,
+ Downstream_MSC_PacketProcessor_RdWrCompleteCallback) == USBH_BUSY)
+ {
+ Downstream_ReleasePacket(receivedPacket);
+ return;
+ }
+
+ //Fail:
+ Downstream_PacketProcessor_ClassReply(receivedPacket);
+}
+
+
+static void Downstream_MSC_PacketProcessor_RdWrCompleteCallback(USBH_StatusTypeDef result)
+{
+ if (result != USBH_OK)
+ {
+ Downstream_GetFreePacket(Downstream_PacketProcessor_GenericErrorReply);
+ return;
+ }
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+}
+
+
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+static void Downstream_MSC_PacketProcessor_BeginWrite(DownstreamPacketTypeDef* receivedPacket)
+{
+ uint64_t writeBlockAddress;
+ uint32_t writeBlockCount;
+ uint64_t writeByteCount;
+ MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
+
+ if (receivedPacket->Length16 != (DOWNSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2)))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ writeBlockAddress = *(uint64_t*)&(receivedPacket->Data[0]);
+ writeBlockCount = *(uint32_t*)&(receivedPacket->Data[8]);
+ writeByteCount = writeBlockCount * MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
+ if ((writeBlockAddress >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
+ ((writeBlockAddress + writeBlockCount - 1) >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
+ (writeByteCount > UINT32_MAX))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ ReadStreamPacket = NULL; //Prepare for GetStreamDataPacket's use
+ ReadStreamBusy = 0;
+ ByteCount = (uint32_t)writeByteCount;
+
+ receivedPacket->Data[0] = HAL_ERROR;
+ receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
+
+ //Our host stack has no way to detect if write-protection is enabled.
+ //So currently we can't return HAL_BUSY to Upstream in this situation.
+ if (USBH_MSC_Write(&hUsbHostFS,
+ MSC_FIXED_LUN,
+ (uint32_t)writeBlockAddress,
+ writeBlockCount,
+ Downstream_MSC_PacketProcessor_RdWrCompleteCallback) == USBH_BUSY)
+ {
+ Downstream_ReleasePacket(receivedPacket);
+ return;
+ }
+
+ //Fail:
+ Downstream_PacketProcessor_ClassReply(receivedPacket);
+}
+#endif
+
+
+//Used by USB MSC host driver
+HAL_StatusTypeDef Downstream_MSC_PutStreamDataPacket(DownstreamPacketTypeDef* packetToSend,
+ uint32_t dataLength8)
+{
+ if ((dataLength8 % 2) != 0)
+ {
+ return HAL_ERROR;
+ }
+
+ packetToSend->Length16 = (dataLength8 / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16;
+ packetToSend->CommandClass = COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG;
+ packetToSend->Command = COMMAND_MSC_READ;
+ return Downstream_TransmitPacket(packetToSend);
+}
+
+
+#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+//Used by USB MSC host driver
+HAL_StatusTypeDef Downstream_MSC_GetStreamDataPacket(DownstreamMSCCallbackPacketTypeDef callback)
+{
+ GetStreamDataCallback = callback;
+
+ if (ReadStreamBusy != 0)
+ {
+ return HAL_OK;
+ }
+ ReadStreamBusy = 1;
+
+ if (ReadStreamPacket && GetStreamDataCallback) //Do we have a stored packet and an address to send it?
+ {
+ Downstream_MSC_GetStreamDataPacketCallback(ReadStreamPacket); //Send it now!
+ ReadStreamPacket = NULL;
+ return HAL_OK; //Our callback will call us again, so we don't need to get a packet in this case.
+ }
+ return Downstream_ReceivePacket(Downstream_MSC_GetStreamDataPacketCallback);
+}
+
+
+void Downstream_MSC_GetStreamDataPacketCallback(DownstreamPacketTypeDef* receivedPacket)
+{
+ uint16_t dataLength8;
+
+ ReadStreamBusy = 0;
+ if (GetStreamDataCallback == NULL)
+ {
+ ReadStreamPacket = receivedPacket; //We used up our callback already, so save this one for later.
+ return;
+ }
+
+ dataLength8 = (receivedPacket->Length16 - DOWNSTREAM_PACKET_HEADER_LEN_16) * 2;
+
+ if ((receivedPacket->CommandClass != (COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG)) || //Must be MSC command with data flag set
+ (receivedPacket->Command != COMMAND_MSC_WRITE) || //Must be write command
+ (receivedPacket->Length16 <= DOWNSTREAM_PACKET_HEADER_LEN_16) || //Should be at least one data byte in the packet.
+ (dataLength8 > ByteCount))
+ {
+ Downstream_PacketProcessor_FreakOut();
+ return;
+ }
+
+ ByteCount -= dataLength8;
+ GetStreamDataCallback(receivedPacket, dataLength8); //usb_msc_scsi will use this packet, so don't release now
+ if (ByteCount > 0)
+ {
+ Downstream_MSC_GetStreamDataPacket(NULL); //Try to get the next packet now, before USB asks for it
+ }
+
+}
+#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
+
+
+
+static void Downstream_MSC_PacketProcessor_Disconnect(DownstreamPacketTypeDef* receivedPacket)
+{
+ Downstream_ReleasePacket(receivedPacket);
+
+ USBH_MSC_StartStopUnit(&hUsbHostFS,
+ MSC_FIXED_LUN,
+ MSC_START_STOP_EJECT_FLAG,
+ Downstream_MSC_PacketProcessor_DisconnectCallback);
+}
+
+
+
+static void Downstream_MSC_PacketProcessor_DisconnectCallback(USBH_StatusTypeDef result)
+{
+ DownstreamPacketTypeDef* freePacket;
+
+ if (result == USBH_OK)
+ {
+ freePacket = Downstream_GetFreePacketImmediately();
+ freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
+ freePacket->Command = COMMAND_MSC_DISCONNECT;
+ freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
+ Downstream_PacketProcessor_ClassReply(freePacket);
+ }
+}
+
+#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED
+
diff --git a/Downstream/Src/downstream_spi.c b/Downstream/Src/downstream_spi.c
new file mode 100644
index 0000000..18f8b03
--- /dev/null
+++ b/Downstream/Src/downstream_spi.c
@@ -0,0 +1,419 @@
+/*
+ * upstream_spi.c
+ *
+ * Created on: 24/07/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+#include "downstream_interface_def.h"
+#include "downstream_spi.h"
+#include "downstream_statemachine.h"
+#include "board_config.h"
+#include "led.h"
+
+
+SPI_HandleTypeDef Hspi1;
+DownstreamPacketTypeDef DownstreamPacket0;
+DownstreamPacketTypeDef DownstreamPacket1;
+DownstreamPacketTypeDef* CurrentWorkingPacket;
+DownstreamPacketTypeDef* NextTxPacket = NULL;
+
+InterfaceStateTypeDef DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
+FreePacketCallbackTypeDef PendingFreePacketCallback = NULL; //Indicates someone is waiting for a packet buffer to become available
+SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates someone is waiting for a received packet
+
+uint32_t TemporaryIncomingPacketLength = 0;
+uint8_t SpiInterruptCompleted = 0;
+
+
+HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void);
+void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket);
+
+
+
+void Downstream_InitSPI(void)
+{
+ DownstreamPacket0.Busy = NOT_BUSY;
+ DownstreamPacket1.Busy = NOT_BUSY;
+
+ Hspi1.Instance = SPI1;
+ Hspi1.Init.Mode = SPI_MODE_SLAVE;
+ Hspi1.Init.Direction = SPI_DIRECTION_2LINES;
+ Hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
+ Hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
+ Hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
+ Hspi1.Init.NSS = SPI_NSS_HARD_INPUT;
+ Hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
+ Hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
+ Hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
+ Hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_ENABLE;
+ Hspi1.Init.CRCPolynomial = SPI_CRC_DEFAULTPOLYNOMIAL;
+ HAL_SPI_Init(&Hspi1);
+}
+
+
+//Used by downstream state machine and USB host classes.
+HAL_StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return HAL_ERROR;
+ }
+
+ //Do we already have a queued callback?
+ if (PendingFreePacketCallback != NULL)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+
+ //Check if there is a free buffer now
+ if (DownstreamPacket0.Busy == NOT_BUSY)
+ {
+ DownstreamPacket0.Busy = BUSY;
+ callback(&DownstreamPacket0);
+ return HAL_OK;
+ }
+ if (DownstreamPacket1.Busy == NOT_BUSY)
+ {
+ DownstreamPacket1.Busy = BUSY;
+ callback(&DownstreamPacket1);
+ return HAL_OK;
+ }
+
+ //Otherwise save requested address for when a buffer becomes free in the future
+ PendingFreePacketCallback = callback;
+ return HAL_OK;
+}
+
+
+
+DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return NULL;
+ }
+
+ //We are expecting a free buffer now
+ if (DownstreamPacket0.Busy == NOT_BUSY)
+ {
+ DownstreamPacket0.Busy = BUSY;
+ return &DownstreamPacket0;
+ }
+ if (DownstreamPacket1.Busy == NOT_BUSY)
+ {
+ DownstreamPacket1.Busy = BUSY;
+ return &DownstreamPacket1;
+ }
+
+ //Should not happen:
+ DOWNSTREAM_SPI_FREAKOUT;
+ return NULL;
+}
+
+
+
+//Used by Downstream state machine and USB host classes.
+void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease)
+{
+ FreePacketCallbackTypeDef tempCallback;
+
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return;
+ }
+
+ if ((packetToRelease != &DownstreamPacket0) &&
+ (packetToRelease != &DownstreamPacket1))
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+
+ if (PendingFreePacketCallback != NULL)
+ {
+ tempCallback = PendingFreePacketCallback; //In extreme situations, running this callback can trigger another request for a free packet,
+ PendingFreePacketCallback = NULL; //thereby causing GetFreePacket to freak out. So we need to clear the callback indicator first.
+ tempCallback(packetToRelease);
+ }
+ else
+ {
+ packetToRelease->Busy = NOT_BUSY;
+ }
+}
+
+
+//Used by Downstream state machine and USB classes.
+//Ok to call when idle or transmitting.
+//Not OK to call when receiving or awaiting reception.
+HAL_StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return HAL_ERROR;
+ }
+
+ if ((DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT) ||
+ (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT) ||
+ (ReceivePacketCallback != NULL))
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+
+ ReceivePacketCallback = callback;
+ return Downstream_CheckPreparePacketReception();
+}
+
+
+//Internal use only
+HAL_StatusTypeDef Downstream_CheckPreparePacketReception(void)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return HAL_ERROR;
+ }
+
+ if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_IDLE)
+ {
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_SIZE_WAIT;
+ return Downstream_GetFreePacket(Downstream_PrepareReceivePacketSize);
+ }
+ return HAL_OK;
+}
+
+
+//Internal use only
+void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return;
+ }
+
+ if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ CurrentWorkingPacket = freePacket;
+ CurrentWorkingPacket->Length16 = 0;
+ if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
+ (uint8_t*)&CurrentWorkingPacket->Length16,
+ (uint8_t*)&CurrentWorkingPacket->Length16,
+ 2) != HAL_OK) //We only need to read one word, but the peripheral library freaks out...
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+
+ UPSTREAM_TX_REQUEST_ASSERT;
+}
+
+
+
+//Used by Downstream state machine and USB classes.
+//Call when idle or transmitting.
+//It doesn't make sense to call when receiving or awaiting reception.
+HAL_StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite)
+{
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return HAL_ERROR;
+ }
+
+ //Sanity checks
+ if ((packetToWrite != &DownstreamPacket0) &&
+ (packetToWrite != &DownstreamPacket1))
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+ if ((packetToWrite->Busy != BUSY) ||
+ (packetToWrite->Length16 < DOWNSTREAM_PACKET_LEN_MIN_16) ||
+ (packetToWrite->Length16 > DOWNSTREAM_PACKET_LEN_16))
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+ if (NextTxPacket != NULL)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+
+ switch (DownstreamInterfaceState)
+ {
+ case DOWNSTREAM_INTERFACE_TX_SIZE_WAIT:
+ case DOWNSTREAM_INTERFACE_TX_PACKET_WAIT:
+ NextTxPacket = packetToWrite;
+ break;
+
+ case DOWNSTREAM_INTERFACE_IDLE:
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_SIZE_WAIT;
+ CurrentWorkingPacket = packetToWrite;
+
+ if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
+ (uint8_t*)&CurrentWorkingPacket->Length16,
+ (uint8_t*)&TemporaryIncomingPacketLength,
+ 2) != HAL_OK) //We only need to write one word, but the peripheral library freaks out...
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+ UPSTREAM_TX_REQUEST_ASSERT;
+ break;
+
+ default:
+ DOWNSTREAM_SPI_FREAKOUT;
+ return HAL_ERROR;
+ }
+
+ return HAL_OK;
+}
+
+
+
+//Do stuff at main loop priority after SPI transaction is complete
+void Downstream_SPIProcess(void)
+{
+ SpiPacketReceivedCallbackTypeDef tempPacketCallback;
+
+ if (SpiInterruptCompleted == 0)
+ {
+ return;
+ }
+ SpiInterruptCompleted = 0;
+
+ if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
+ {
+ return;
+ }
+
+ //Finished transmitting packet size
+ if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_TX_SIZE_WAIT)
+ {
+ if ((uint16_t)TemporaryIncomingPacketLength != 0)
+ {
+ //Currently we just freak out if Upstream sends us an unexpected command.
+ //Theoretically we could reset our downstream state machine and accept the new command...
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_PACKET_WAIT;
+ if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
+ &CurrentWorkingPacket->CommandClass,
+ &CurrentWorkingPacket->CommandClass,
+ ((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ UPSTREAM_TX_REQUEST_ASSERT;
+ return;
+ }
+
+ //Finished transmitting packet body
+ if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_TX_PACKET_WAIT)
+ {
+ Downstream_ReleasePacket(CurrentWorkingPacket);
+ if (NextTxPacket != NULL)
+ {
+ //NextTxPacket has already passed the checks in Downstream_TransmitPacket.
+ //So we just need to pass it to HAL_SPI_Transmit_DMA.
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_SIZE_WAIT;
+ CurrentWorkingPacket = NextTxPacket;
+ NextTxPacket = NULL;
+ if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
+ (uint8_t*)&CurrentWorkingPacket->Length16,
+ (uint8_t*)&TemporaryIncomingPacketLength,
+ 2) != HAL_OK) //We only need to write one word, but the peripheral library freaks out...
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ UPSTREAM_TX_REQUEST_ASSERT;
+ return;
+ }
+
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
+ if (ReceivePacketCallback != NULL)
+ {
+ Downstream_CheckPreparePacketReception();
+ }
+ return;
+ }
+
+
+ if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
+ {
+ if ((CurrentWorkingPacket->Length16 < DOWNSTREAM_PACKET_LEN_MIN_16) ||
+ (CurrentWorkingPacket->Length16 > DOWNSTREAM_PACKET_LEN_16))
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_PACKET_WAIT;
+ if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
+ &CurrentWorkingPacket->CommandClass,
+ &CurrentWorkingPacket->CommandClass,
+ ((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ UPSTREAM_TX_REQUEST_ASSERT;
+ return;
+ }
+
+ if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT)
+ {
+ DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
+ if (ReceivePacketCallback == NULL)
+ {
+ DOWNSTREAM_SPI_FREAKOUT;
+ return;
+ }
+ //Packet processor may want to receive another packet immediately,
+ //so clear ReceivePacketCallback before the call.
+ //It is the callback's responsibility to release the packet buffer we are passing to it!
+ tempPacketCallback = ReceivePacketCallback;
+ ReceivePacketCallback = NULL;
+ tempPacketCallback(CurrentWorkingPacket);
+ return;
+ }
+
+
+ //case default:
+ DOWNSTREAM_SPI_FREAKOUT;
+}
+
+
+
+//Called at the end of the SPI TxRx DMA transfer,
+//at DMA2 interrupt priority. Assume *hspi points to our hspi1.
+//We use TxRx to send our reply packet to check if Upstream was trying
+//to send us a packet at the same time.
+//We also TxRx our packet body because the SPI silicon is buggy at the end of
+//a transmit-only DMA transfer with CRC! (it does not clear RXNE flag on request)
+void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
+{
+ UPSTREAM_TX_REQUEST_DEASSERT;
+ SpiInterruptCompleted = 1;
+}
+
+
+
+//Something bad happened! Possibly CRC error...
+void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
+{
+ DOWNSTREAM_SPI_FREAKOUT;
+}
+
diff --git a/Downstream/Src/downstream_statemachine.c b/Downstream/Src/downstream_statemachine.c
new file mode 100644
index 0000000..66c5490
--- /dev/null
+++ b/Downstream/Src/downstream_statemachine.c
@@ -0,0 +1,338 @@
+/*
+ * downstream_statemachine.c
+ *
+ * Created on: 2/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+#include "downstream_statemachine.h"
+#include "downstream_interface_def.h"
+#include "downstream_spi.h"
+#include "downstream_msc.h"
+#include "downstream_hid.h"
+#include "usbh_core.h"
+#include "usbh_msc.h"
+#include "usbh_hid.h"
+#include "led.h"
+#include "build_config.h"
+
+
+DownstreamStateTypeDef DownstreamState = STATE_DEVICE_NOT_READY;
+InterfaceCommandClassTypeDef ConfiguredDeviceClass = COMMAND_CLASS_INTERFACE;
+uint8_t NotifyDisconnectReply = 0;
+
+
+static void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket);
+static void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketTypeDef* replyPacket);
+static void Downstream_PacketProcessor_NotifyDisconnectReply(DownstreamPacketTypeDef* packetToSend);
+
+
+#ifdef CONFIG_USB_ID_ENABLED
+
+//usb device id def
+typedef struct usb_id{
+ uint16_t vendor;
+ uint16_t product;
+}usb_device_id;
+
+#define USB_ID_COUNT 2
+
+usb_device_id list[USB_ID_COUNT]={
+ {0x046d,0xc077},//usb vendor,usb product, add your device to array and edit USB_ID_COUNT
+ // {0x046d,0xc0ff} //bad device test
+ {0x12c9,0x1017} //new mouse Fury
+};
+#endif
+
+void Downstream_InitStateMachine(void)
+{
+ if ((DownstreamState != STATE_DEVICE_NOT_READY) ||
+ (ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE))
+ {
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ return;
+ }
+
+ Downstream_InitSPI();
+
+ //Prepare to receive our first packet from Upstream!
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+}
+
+
+
+void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
+{
+ if (DownstreamState >= STATE_ERROR)
+ {
+ Downstream_ReleasePacket(receivedPacket);
+ return;
+ }
+
+ //Device not connected yet
+ if (DownstreamState != STATE_ACTIVE)
+ {
+ if (receivedPacket->CommandClass == COMMAND_CLASS_INTERFACE)
+ {
+ Downstream_PacketProcessor_Interface(receivedPacket);
+ }
+ else
+ {
+ //If we get a class-specific message when our device is disconnected,
+ //we need to tell Upstream of the fact (and not freak out).
+ Downstream_PacketProcessor_NotifyDisconnectReply(receivedPacket);
+ }
+ return;
+ }
+
+ //Device is connected: expect only class-specific messages,
+ //and only to our currently active device class.
+ if ((ConfiguredDeviceClass == COMMAND_CLASS_INTERFACE) ||
+ (ConfiguredDeviceClass != receivedPacket->CommandClass))
+ {
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ return;
+ }
+
+ switch (ConfiguredDeviceClass)
+ {
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+ case COMMAND_CLASS_MASS_STORAGE:
+ Downstream_MSC_PacketProcessor(receivedPacket);
+ break;
+#endif
+#ifdef CONFIG_MOUSE_ENABLED
+ case COMMAND_CLASS_HID_MOUSE:
+ Downstream_HID_PacketProcessor(receivedPacket);
+ break;
+#endif
+#ifdef CONFIG_KEYBOARD_ENABLED
+ case COMMAND_CLASS_HID_KEYBOARD:
+ Downstream_HID_PacketProcessor(receivedPacket);
+ break;
+#endif
+
+ //Add other classes here...
+
+ default:
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ }
+}
+
+
+
+//Used by downstream class interfaces, and SPI interface
+void Downstream_PacketProcessor_FreakOut(void)
+{
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+}
+
+
+
+void Downstream_PacketProcessor_Interface(DownstreamPacketTypeDef* receivedPacket)
+{
+ switch (receivedPacket->Command)
+ {
+ case COMMAND_INTERFACE_ECHO:
+ Downstream_TransmitPacket(receivedPacket);
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+ break;
+
+ case COMMAND_INTERFACE_NOTIFY_DEVICE:
+ if (DownstreamState == STATE_DEVICE_READY)
+ {
+ Downstream_PacketProcessor_Interface_ReplyNotifyDevice(receivedPacket);
+ return;
+ }
+
+ if (DownstreamState == STATE_DEVICE_NOT_READY)
+ {
+ DownstreamState = STATE_WAIT_DEVICE_READY;
+ Downstream_ReleasePacket(receivedPacket);
+ return;
+ }
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ break;
+
+
+ default:
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ }
+}
+
+
+void Downstream_PacketProcessor_Interface_ReplyNotifyDevice(DownstreamPacketTypeDef* replyPacket)
+{
+ replyPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
+ replyPacket->CommandClass = COMMAND_CLASS_INTERFACE;
+ replyPacket->Command = COMMAND_INTERFACE_NOTIFY_DEVICE;
+ replyPacket->Data[0] = ConfiguredDeviceClass;
+
+ if (Downstream_TransmitPacket(replyPacket) == HAL_OK)
+ {
+ DownstreamState = STATE_ACTIVE;
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+ }
+}
+
+
+void Downstream_PacketProcessor_GenericErrorReply(DownstreamPacketTypeDef* replyPacket)
+{
+ replyPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
+ replyPacket->CommandClass = COMMAND_CLASS_ERROR;
+ replyPacket->Command = COMMAND_ERROR_GENERIC;
+
+ Downstream_TransmitPacket(replyPacket);
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+ NotifyDisconnectReply = 0;
+}
+
+
+void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket)
+{
+ Downstream_TransmitPacket(replyPacket);
+ Downstream_ReceivePacket(Downstream_PacketProcessor);
+ NotifyDisconnectReply = 0;
+}
+
+
+void Downstream_PacketProcessor_NotifyDisconnectReplyRequired(void)
+{
+ NotifyDisconnectReply = 1;
+}
+
+
+void Downstream_PacketProcessor_CheckNotifyDisconnectReply(void)
+{
+ if (NotifyDisconnectReply == 2)
+ {
+ Downstream_GetFreePacket(Downstream_PacketProcessor_NotifyDisconnectReply);
+ }
+}
+
+
+void Downstream_PacketProcessor_NotifyDisconnectReply(DownstreamPacketTypeDef* packetToSend)
+{
+ packetToSend->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
+ packetToSend->CommandClass = COMMAND_CLASS_ERROR;
+ packetToSend->Command = COMMAND_ERROR_DEVICE_DISCONNECTED;
+ Downstream_PacketProcessor_ClassReply(packetToSend);
+}
+
+
+//This callback receives various event ids from the host stack,
+//either at INT_PRIORITY_OTG_FS or from main().
+void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
+{
+ InterfaceCommandClassTypeDef newActiveClass = COMMAND_CLASS_INTERFACE;
+
+ if (DownstreamState >= STATE_ERROR)
+ {
+ return;
+ }
+
+ //Called from USB interrupt.
+ //Simple function shouldn't need to worry about preempting anything important.
+ if (id == HOST_USER_DISCONNECTION)
+ {
+ DownstreamState = STATE_DEVICE_NOT_READY;
+ if (NotifyDisconnectReply == 1)
+ {
+ NotifyDisconnectReply = 2; //Request a 'device disconnected' reply when we get back to main()
+ }
+ return;
+ }
+
+
+ //Called from main()
+ if (id == HOST_USER_CLASS_ACTIVE)
+ {
+#ifdef CONFIG_USB_ID_ENABLED
+ //check vendor product id
+ for(int i=0;idevice.DevDesc.idVendor && list[i].product==phost->device.DevDesc.idProduct){
+ break;
+ }else{
+ if(i==(USB_ID_COUNT-1)){//last usb device in list
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ }
+ }
+ }
+#endif
+
+ switch (phost->pActiveClass->ClassCode)
+ {
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+ case USB_MSC_CLASS:
+ newActiveClass = Downstream_MSC_ApproveConnectedDevice();
+ break;
+#endif
+#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+ case USB_HID_CLASS:
+ newActiveClass = Downstream_HID_ApproveConnectedDevice();
+ break;
+#endif
+
+ //Add other classes here...
+
+
+ }
+
+ //Unsupported device classes will cause a slow fault flash.
+ //This is distinct from the fast freakout flash caused by internal errors or attacks.
+ //We consider supported classes that fail their approval checks to also be unsupported devices.
+ if (newActiveClass == COMMAND_CLASS_INTERFACE)
+ {
+ USB_Host_Disconnect();
+ LED_SetState(LED_STATUS_FLASH_UNSUPPORTED);
+ DownstreamState = STATE_ERROR;
+ return;
+ }
+
+ //If we already configured a device class, we cannot change to a different one without rebooting.
+ //This blocks 'hidden device' BadUSB attacks.
+ if ((ConfiguredDeviceClass != COMMAND_CLASS_INTERFACE) &&
+ (ConfiguredDeviceClass != newActiveClass))
+ {
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ return;
+ }
+ ConfiguredDeviceClass = newActiveClass;
+
+ if (DownstreamState == STATE_WAIT_DEVICE_READY)
+ {
+ Downstream_GetFreePacket(Downstream_PacketProcessor_Interface_ReplyNotifyDevice);
+ return;
+ }
+
+ if (DownstreamState == STATE_DEVICE_NOT_READY)
+ {
+ DownstreamState = STATE_DEVICE_READY;
+ return;
+ }
+
+ DOWNSTREAM_STATEMACHINE_FREAKOUT;
+ return;
+ }
+
+
+ //Called from main():
+ if ((id == HOST_USER_CLASS_FAILED) ||
+ (id == HOST_USER_UNRECOVERED_ERROR)) //Probably due to a crappy device that won't enumerate!
+ {
+ //Unsupported device classes will cause a slow fault flash.
+ //This is distinct from the fast freakout flash caused by internal errors or attacks.
+ USB_Host_Disconnect();
+ LED_SetState(LED_STATUS_FLASH_UNSUPPORTED);
+ DownstreamState = STATE_ERROR;
+ return;
+ }
+
+}
+
diff --git a/Downstream/Src/hal_msp.c b/Downstream/Src/hal_msp.c
new file mode 100644
index 0000000..bf1608e
--- /dev/null
+++ b/Downstream/Src/hal_msp.c
@@ -0,0 +1,163 @@
+/**
+ ******************************************************************************
+ * File Name : stm32f4xx_hal_msp.c
+ * Description : This file provides code for the MSP Initialization
+ * and de-Initialization codes.
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_hal.h"
+#include "interrupts.h"
+#include "board_config.h"
+
+
+DMA_HandleTypeDef hdma_spi1_rx;
+DMA_HandleTypeDef hdma_spi1_tx;
+
+
+
+void HAL_MspInit(void)
+{
+
+ HAL_NVIC_SetPriority(SysTick_IRQn, INT_PRIORITY_SYSTICK, 0);
+}
+
+
+uint32_t HAL_GetHSECrystalFreqMHz(void)
+{
+ if ((BOARD_REV_ID_PORT->IDR & BOARD_REV_PIN_MASK) < BOARD_REV_1_0_BETA_3)
+ {
+ return BOARD_REV_1_0_BETA_FREQ;
+ }
+ else
+ {
+ return BOARD_REV_1_0_BETA_3_FREQ;
+ }
+}
+
+
+void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ if(hspi->Instance==SPI1)
+ {
+ __SPI1_CLK_ENABLE();
+ __DMA2_CLK_ENABLE();
+
+ /**SPI1 GPIO Configuration
+ PA4 ------> SPI_NSS
+ PA5 ------> SPI1_SCK
+ PA6 ------> SPI1_MISO
+ PA7 ------> SPI1_MOSI
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_4; //NSS is active low so pull up
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM;
+ GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; //SCK & data are active high so pull down
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ UPSTREAM_TX_REQUEST_DEASSERT;
+ GPIO_InitStruct.Pin = UPSTREAM_TX_REQUEST_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(UPSTREAM_TX_REQUEST_PORT, &GPIO_InitStruct);
+
+ /* Peripheral DMA init*/
+ hdma_spi1_rx.Instance = DMA2_Stream2;
+ hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
+ hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ hdma_spi1_rx.Init.Mode = DMA_NORMAL;
+ hdma_spi1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
+ hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ HAL_DMA_Init(&hdma_spi1_rx);
+ __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
+
+ hdma_spi1_tx.Instance = DMA2_Stream3;
+ hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
+ hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ hdma_spi1_tx.Init.Mode = DMA_NORMAL;
+ hdma_spi1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
+ hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ HAL_DMA_Init(&hdma_spi1_tx);
+ __HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);
+
+ /* DMA interrupt init */
+ HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, INT_PRIORITY_SPI_DMA, 0);
+ HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
+ HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, INT_PRIORITY_SPI_DMA, 0);
+ HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
+
+ }
+}
+
+
+void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
+{
+
+ if(hspi->Instance==SPI1)
+ {
+ __SPI1_CLK_DISABLE();
+
+ /**SPI1 GPIO Configuration
+ PA5 ------> SPI1_SCK
+ PA6 ------> SPI1_MISO
+ PA7 ------> SPI1_MOSI
+ */
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
+
+ /* Peripheral DMA DeInit*/
+ HAL_DMA_DeInit(hspi->hdmarx);
+ HAL_DMA_DeInit(hspi->hdmatx);
+ }
+
+}
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Src/interrupts.c b/Downstream/Src/interrupts.c
new file mode 100644
index 0000000..f7393fd
--- /dev/null
+++ b/Downstream/Src/interrupts.c
@@ -0,0 +1,117 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_it.c
+ * @brief Interrupt Service Routines.
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_hal.h"
+#include "stm32f4xx.h"
+#include "interrupts.h"
+#include "led.h"
+#include "board_config.h"
+
+
+/* External variables --------------------------------------------------------*/
+extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
+extern DMA_HandleTypeDef hdma_spi1_rx;
+extern DMA_HandleTypeDef hdma_spi1_tx;
+
+extern volatile uint8_t UsbInterruptHasHappened;
+
+uint8_t BusFaultAllowed = 0;
+
+
+/******************************************************************************/
+/* Cortex-M4 Processor Interruption and Exception Handlers */
+/******************************************************************************/
+
+/**
+* @brief This function handles System tick timer.
+*/
+void SysTick_Handler(void)
+{
+ HAL_IncTick();
+ LED_Tick();
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripheral Interrupt Handlers */
+/* Add here the Interrupt Handlers for the used peripherals. */
+/* For the available peripheral interrupt handler names, */
+/* please refer to the startup file (startup_stm32f4xx.s). */
+/******************************************************************************/
+
+
+
+void DMA2_Stream2_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(&hdma_spi1_rx);
+}
+
+void DMA2_Stream3_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(&hdma_spi1_tx);
+}
+
+void OTG_FS_IRQHandler(void)
+{
+ HAL_HCD_IRQHandler(&hhcd_USB_OTG_FS);
+ UsbInterruptHasHappened = 1;
+}
+
+
+//This weird stuff is required when disabling flash writes.
+//The deliberate flash lockout will cause a bus fault that we need to process.
+void EnableOneBusFault(void)
+{
+ //It should not be enabled already!
+ if (BusFaultAllowed)
+ {
+ while (1);
+ }
+ SCB->SHCSR = SCB_SHCSR_BUSFAULTENA_Msk;
+ BusFaultAllowed = 1;
+}
+
+void BusFault_Handler(void)
+{
+ if (BusFaultAllowed)
+ {
+ BusFaultAllowed = 0;
+ return;
+ }
+ while (1);
+}
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Src/led.c b/Downstream/Src/led.c
new file mode 100644
index 0000000..a6da5ac
--- /dev/null
+++ b/Downstream/Src/led.c
@@ -0,0 +1,142 @@
+/*
+ * led.c
+ *
+ * Created on: 19/08/2015
+ * Author: Robert Fisk
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+
+#include "led.h"
+#include "board_config.h"
+#include "build_config.h"
+
+uint32_t FaultLedCounter;
+uint32_t ReadWriteFlashEndTime;
+
+LedStatusTypeDef FaultLedState;
+uint16_t FaultLedOnMs;
+uint16_t FaultLedOffMs;
+uint8_t FaultLedBlinkCount;
+
+uint8_t FaultLedBlinkCountState;
+uint8_t FaultLedOutputState;
+
+
+void LED_Init(void)
+{
+ FAULT_LED_ON;
+ ReadWriteFlashEndTime = 0;
+ FaultLedState = LED_STATUS_STARTUP;
+}
+
+
+void LED_SetState(LedStatusTypeDef newState)
+{
+ switch (newState)
+ {
+ case LED_STATUS_OFF:
+ FaultLedCounter = UINT32_MAX;
+ FaultLedBlinkCountState = 0;
+ FaultLedOutputState = 0;
+ FAULT_LED_OFF;
+ break;
+
+ case LED_STATUS_FLASH_UNSUPPORTED:
+ FaultLedOnMs = LED_UNSUPPORTED_BLINK_MS;
+ FaultLedOffMs = LED_UNSUPPORTED_BLINK_MS;
+ FaultLedBlinkCount = 1;
+ break;
+
+ case LED_STATUS_FLASH_BOTDETECT:
+ FaultLedOnMs = LED_BOTDETECT_ON_MS;
+ FaultLedOffMs = LED_BOTDETECT_OFF_MS;
+ FaultLedBlinkCount = 2;
+ break;
+
+ case LED_STATUS_FLASH_READWRITE:
+#ifdef CONFIG_READ_FLASH_TIME_MS
+ if (FaultLedState == LED_STATUS_OFF)
+ {
+ FaultLedOnMs = LED_READWRITE_ON_MS;
+ FaultLedOffMs = LED_READWRITE_OFF_MS;
+ FaultLedBlinkCount = 1;
+ ReadWriteFlashEndTime = HAL_GetTick() + CONFIG_READ_FLASH_TIME_MS;
+ }
+ else
+#endif
+ {
+ newState = FaultLedState; //Don't override other active states
+ }
+ break;
+
+ default:
+ FaultLedOnMs = LED_ERROR_BLINK_MS; //Everything else is LED_STATUS_ERROR
+ FaultLedOffMs = LED_ERROR_BLINK_MS;
+ FaultLedBlinkCount = 1;
+ }
+
+ FaultLedState = newState;
+}
+
+
+void LED_Tick(void)
+{
+ if (FaultLedState == LED_STATUS_OFF) return;
+
+ if (FaultLedState == LED_STATUS_STARTUP)
+ {
+ if (HAL_GetTick() >= STARTUP_FLASH_DELAY_MS)
+ {
+ LED_SetState(LED_STATUS_OFF);
+ }
+ return;
+ }
+
+#ifdef CONFIG_READ_FLASH_TIME_MS
+ if (FaultLedState == LED_STATUS_FLASH_READWRITE)
+ {
+ if ((int32_t)(HAL_GetTick() - ReadWriteFlashEndTime) > 0)
+ {
+ LED_SetState(LED_STATUS_OFF);
+ return;
+ }
+ }
+#endif
+
+ if (FaultLedOutputState)
+ {
+ if (FaultLedCounter++ >= FaultLedOnMs) //Check to turn LED off
+ {
+ FaultLedBlinkCountState++;
+ FaultLedCounter = 0;
+ FaultLedOutputState = 0;
+ FAULT_LED_OFF;
+ }
+ }
+ else
+ {
+ if (FaultLedBlinkCountState >= FaultLedBlinkCount) //Checks to turn LED on...
+ {
+ if (FaultLedCounter++ >= FaultLedOffMs) //Last flash may have longer off-time
+ {
+ FaultLedBlinkCountState = 0;
+ FaultLedCounter = 0;
+ FaultLedOutputState = 1;
+ FAULT_LED_ON;
+ }
+ }
+ else
+ {
+ if (FaultLedCounter++ >= FaultLedOnMs) //Flash sequence uses on-time as intermediate off-time
+ {
+ FaultLedCounter = 0;
+ FaultLedOutputState = 1;
+ FAULT_LED_ON;
+ }
+ }
+ }
+}
diff --git a/Downstream/Src/main.c b/Downstream/Src/main.c
new file mode 100644
index 0000000..5ee813c
--- /dev/null
+++ b/Downstream/Src/main.c
@@ -0,0 +1,286 @@
+/**
+ ******************************************************************************
+ * File Name : main.c
+ * Description : Main program body
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_hal.h"
+#include "usb_host.h"
+#include "board_config.h"
+#include "downstream_statemachine.h"
+#include "downstream_spi.h"
+#include "led.h"
+#include "interrupts.h"
+#include "build_config.h"
+
+
+
+/* Private function prototypes -----------------------------------------------*/
+static void SystemClock_Config(void);
+static void GPIO_Init(void);
+static void DisableFlashWrites(void);
+static void CheckFirmwareMatchesHardware(void);
+static void SetRDPlevel(void);
+
+FLASH_OBProgramInitTypeDef flash_OBinit;
+
+volatile uint8_t UsbInterruptHasHappened = 0;
+uint8_t IterationCount = 0;
+
+
+int main(void)
+{
+ //First things first!
+// DisableFlashWrites();
+ CheckFirmwareMatchesHardware();
+
+ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
+ HAL_Init();
+
+#ifdef CONFIG_FLASH_RDP_ENABLE
+ SetRDPlevel();
+#endif
+
+ /* Configure the system clock */
+ SystemClock_Config();
+
+ /* Initialize all configured peripherals */
+ GPIO_Init();
+ LED_Init();
+ USB_Host_Init();
+
+ Downstream_InitStateMachine();
+
+ while (1)
+ {
+ USB_Host_Process();
+ Downstream_SPIProcess();
+ Downstream_PacketProcessor_CheckNotifyDisconnectReply();
+
+ //Count number of main loops since last USB interrupt
+ if (UsbInterruptHasHappened)
+ {
+ UsbInterruptHasHappened = 0;
+ IterationCount = 0;
+ }
+
+ //Some USB host state transitions take 3 iterations to fully apply.
+ //We'll be generous and give it 5 before sleeping.
+ if (IterationCount++ > 4)
+ {
+ __WFI(); //sleep time!
+ }
+ }
+}
+
+
+void SetRDPlevel(void)
+{
+ HAL_FLASH_Unlock();
+ HAL_FLASH_OB_Unlock();
+ flash_OBinit.OptionType=OPTIONBYTE_RDP;
+ flash_OBinit.RDPLevel=OB_RDP_LEVEL_1;
+ HAL_FLASHEx_OBProgram(&flash_OBinit);
+ HAL_FLASH_OB_Launch();
+ HAL_FLASH_OB_Lock();
+ HAL_FLASH_Lock();
+
+}
+
+void DisableFlashWrites(void)
+{
+ //Disable flash writes until the next reset
+ //This will cause a bus fault interrupt, so allow one now.
+ EnableOneBusFault();
+ FLASH->KEYR = 999;
+
+ //Confirm that flash cannot be unlocked
+ //This unlock attempt will also cause two bus faults.
+ if ((FLASH->CR & FLASH_CR_LOCK) == 0) while(1);
+ EnableOneBusFault();
+ FLASH->KEYR = FLASH_KEY1;
+ EnableOneBusFault();
+ FLASH->KEYR = FLASH_KEY2;
+ if ((FLASH->CR & FLASH_CR_LOCK) == 0) while(1);
+}
+
+
+void CheckFirmwareMatchesHardware(void)
+{
+ //Check we are running on the expected hardware:
+ //STM32F401RC on USG v1.0 beta
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+
+ if ((*(uint32_t*)DBGMCU_BASE & DBGMCU_IDCODE_DEV_ID) == DBGMCU_IDCODE_DEV_ID_401xB_xC)
+ {
+ //Read in board revision and ID on port C
+ GPIO_InitStruct.Pin = BOARD_REV_PIN_MASK | BOARD_ID_PIN_MASK;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ GPIO_InitStruct.Alternate = 0;
+ HAL_GPIO_Init(BOARD_REV_ID_PORT, &GPIO_InitStruct);
+
+ //Correct board revision?
+ if ((BOARD_REV_ID_PORT->IDR & BOARD_REV_PIN_MASK) <= BOARD_REV_1_0_BETA_3)
+ {
+ //Correct board ID: downstream?
+ if (!(BOARD_REV_ID_PORT->IDR & BOARD_ID_PIN_MASK))
+ {
+ return;
+ }
+ }
+ }
+
+ //This is not the hardware we expected, so turn on our fault LED(s) and die in a heap.
+ GPIO_InitStruct.Pin = FAULT_LED_PIN | H405_FAULT_LED_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(FAULT_LED_PORT, &GPIO_InitStruct);
+ FAULT_LED_ON;
+ H405_FAULT_LED_ON;
+ while (1);
+}
+
+
+/** System Clock Configuration
+*/
+void SystemClock_Config(void)
+{
+
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+
+ __PWR_CLK_ENABLE();
+
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLM = (HAL_GetHSECrystalFreqMHz() / 2); //PLL input frequency = 2MHz
+ RCC_OscInitStruct.PLL.PLLN = 168;
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
+ RCC_OscInitStruct.PLL.PLLQ = 7;
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) while (1);
+
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK |
+ RCC_CLOCKTYPE_HCLK |
+ RCC_CLOCKTYPE_PCLK1 |
+ RCC_CLOCKTYPE_PCLK2;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) while (1);
+
+ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
+}
+
+
+
+
+void GPIO_Init(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+
+ /* GPIO Ports Clock Enable */
+ //__GPIOH_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+
+ //Bulk initialise all ports as inputs with pullups active,
+ //excluding JTAG pins which must remain as AF0!
+ GPIO_InitStruct.Pin = (GPIO_PIN_All & ~(PA_JTMS | PA_JTCK | PA_JTDI));
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ GPIO_InitStruct.Alternate = 0;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+ GPIO_InitStruct.Pin = (GPIO_PIN_All & ~(PB_JTDO | PB_NJTRST));
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+ GPIO_InitStruct.Pin = GPIO_PIN_All;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+ //Fault LED is output
+ GPIO_InitStruct.Pin = FAULT_LED_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(FAULT_LED_PORT, &GPIO_InitStruct);
+ FAULT_LED_OFF;
+
+// //SPI_INT_ACTIVE indicator
+// GPIO_InitStruct.Pin = INT_ACTIVE_PIN;
+// HAL_GPIO_Init(INT_ACTIVE_PORT, &GPIO_InitStruct);
+// INT_ACTIVE_OFF;
+}
+
+
+
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief Reports the name of the source file and the source line number
+ * where the assert_param error has occurred.
+ * @param file: pointer to the source file name
+ * @param line: assert_param error line source number
+ * @retval None
+ */
+void assert_failed(uint8_t* file, uint32_t line)
+{
+ /* USER CODE BEGIN 6 */
+ /* User can add his own implementation to report the file name and line number,
+ ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
+ /* USER CODE END 6 */
+
+}
+
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Src/usb_host.c b/Downstream/Src/usb_host.c
new file mode 100644
index 0000000..694d3d8
--- /dev/null
+++ b/Downstream/Src/usb_host.c
@@ -0,0 +1,88 @@
+/**
+ ******************************************************************************
+ * @file : USB_HOST
+ * @version : v1.0_Cube
+ * @brief : This file implements the USB Host
+ ******************************************************************************
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "usb_host.h"
+#include "usbh_core.h"
+#include "usbh_msc.h"
+#include "usbh_hid.h"
+#include "downstream_statemachine.h"
+#include "build_config.h"
+
+
+/* USB Host Core handle declaration */
+USBH_HandleTypeDef hUsbHostFS;
+
+
+/* init function */
+void USB_Host_Init(void)
+{
+ /* Init Host Library,Add Supported Class and Start the library*/
+ USBH_Init(&hUsbHostFS, Downstream_HostUserCallback, HOST_FS);
+
+#ifdef CONFIG_MASS_STORAGE_ENABLED
+ USBH_RegisterClass(&hUsbHostFS, USBH_MSC_CLASS);
+#endif
+#if defined (CONFIG_KEYBOARD_ENABLED) || defined (CONFIG_MOUSE_ENABLED)
+ USBH_RegisterClass(&hUsbHostFS, USBH_HID_CLASS);
+#endif
+
+ USBH_Start(&hUsbHostFS);
+}
+
+/*
+ * Background task
+*/
+void USB_Host_Process()
+{
+ /* USB Host Background task */
+ USBH_Process(&hUsbHostFS);
+
+}
+
+
+//Called when Downstream Statemachine or SPI freaks out.
+void USB_Host_Disconnect()
+{
+ USBH_DeInit(&hUsbHostFS);
+}
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/Src/usbh_config.c b/Downstream/Src/usbh_config.c
new file mode 100644
index 0000000..4d842f0
--- /dev/null
+++ b/Downstream/Src/usbh_config.c
@@ -0,0 +1,470 @@
+/**
+ ******************************************************************************
+ * @file : usbh_conf.c
+ * @version : v1.0_Cube
+ * @brief : This file implements the board support package for the USB host library
+ ******************************************************************************
+ * COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ *
+ * Modifications by Robert Fisk
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "interrupts.h"
+
+
+HCD_HandleTypeDef hhcd_USB_OTG_FS;
+
+
+/*******************************************************************************
+ LL Driver Callbacks (HCD -> USB Host Library)
+*******************************************************************************/
+/* MSP Init */
+
+void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ if(hhcd->Instance==USB_OTG_FS)
+ {
+ /**USB_OTG_FS GPIO Configuration
+ PA11 ------> USB_OTG_FS_DM
+ PA12 ------> USB_OTG_FS_DP
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ /* Peripheral clock enable */
+ __USB_OTG_FS_CLK_ENABLE();
+
+ /* Peripheral interrupt init*/
+ HAL_NVIC_SetPriority(OTG_FS_IRQn, INT_PRIORITY_USB, 0);
+ HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+ }
+}
+
+
+void HAL_HCD_MspDeInit(HCD_HandleTypeDef* hhcd)
+{
+ if(hhcd->Instance==USB_OTG_FS)
+ {
+ /* Peripheral clock disable */
+ __USB_OTG_FS_CLK_DISABLE();
+
+ /**USB_OTG_FS GPIO Configuration
+ PA9 ------> USB_OTG_FS_VBUS
+ PA11 ------> USB_OTG_FS_DM
+ PA12 ------> USB_OTG_FS_DP
+ */
+ //HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
+
+ /* Peripheral interrupt Deinit*/
+ HAL_NVIC_DisableIRQ(OTG_FS_IRQn);
+ }
+}
+
+/**
+ * @brief SOF callback.
+ * @param hhcd: HCD handle
+ * @retval None
+ */
+void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_LL_IncTimer (hhcd->pData);
+}
+
+/**
+ * @brief SOF callback.
+ * @param hhcd: HCD handle
+ * @retval None
+ */
+void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_LL_Connect(hhcd->pData);
+}
+
+
+void HAL_HCD_PortEnabled_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_LL_PortEnabled(hhcd->pData);
+}
+
+
+/**
+ * @brief SOF callback.
+ * @param hhcd: HCD handle
+ * @retval None
+ */
+HAL_StatusTypeDef HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
+{
+ if (USBH_LL_Disconnect(hhcd->pData) == USBH_OK)
+ {
+ return HAL_OK;
+ }
+ return HAL_ERROR;
+}
+
+/**
+ * @brief Notify URB state change callback.
+ * @param hhcd: HCD handle
+ * @retval None
+ */
+void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
+{
+ /* To be used with OS to sync URB state with the global state machine */
+#if (USBH_USE_OS == 1)
+ USBH_LL_NotifyURBChange(hhcd->pData);
+#endif
+}
+/*******************************************************************************
+ LL Driver Interface (USB Host Library --> HCD)
+*******************************************************************************/
+/**
+ * @brief USBH_LL_Init
+ * Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost)
+{
+ /* Init USB_IP */
+ if (phost->id == HOST_FS) {
+ /* Link The driver to the stack */
+ hhcd_USB_OTG_FS.pData = phost;
+ phost->pData = &hhcd_USB_OTG_FS;
+
+ hhcd_USB_OTG_FS.Instance = USB_OTG_FS;
+ hhcd_USB_OTG_FS.Init.Host_channels = 8;
+ hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;
+ hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;
+ hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
+ hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
+ HAL_HCD_Init(&hhcd_USB_OTG_FS);
+
+ USBH_LL_SetTimer (phost, HAL_HCD_GetCurrentFrame(&hhcd_USB_OTG_FS));
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_DeInit
+ * De-Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_DeInit(phost->pData);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Start
+ * Start the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_Start(phost->pData);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Stop
+ * Stop the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_Stop(phost->pData);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetSpeed
+ * Return the USB Host Speed from the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Speeds
+ */
+USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost)
+{
+ USBH_SpeedTypeDef speed = USBH_SPEED_FULL;
+
+ switch (HAL_HCD_GetCurrentSpeed(phost->pData))
+ {
+ case 0 :
+ speed = USBH_SPEED_HIGH;
+ break;
+
+// case 1 :
+// speed = USBH_SPEED_FULL;
+// break;
+
+ case 2 :
+ speed = USBH_SPEED_LOW;
+ break;
+
+// default:
+// speed = USBH_SPEED_FULL;
+// break;
+ }
+ return speed;
+}
+
+/**
+ * @brief USBH_LL_ResetPort
+ * Reset the Host Port of the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_ResetPort(phost->pData);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetLastXferSize
+ * Return the last transfered packet size.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval Packet Size
+ */
+uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return HAL_HCD_HC_GetXferCount(phost->pData, pipe);
+}
+
+/**
+ * @brief USBH_LL_OpenPipe
+ * Open a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @param epnum: Endpoint Number
+ * @param dev_address: Device USB address
+ * @param speed: Device Speed
+ * @param ep_type: Endpoint Type
+ * @param mps: Endpoint Max Packet Size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+ HAL_HCD_HC_Init(phost->pData,
+ pipe_num,
+ epnum,
+ dev_address,
+ speed,
+ ep_type,
+ mps);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_ClosePipe
+ * Close a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ HAL_HCD_HC_Halt(phost->pData, pipe);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SubmitURB
+ * Submit a new URB to the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @param direction : Channel number
+ * This parameter can be one of the these values:
+ * 0 : Output
+ * 1 : Input
+ * @param ep_type : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg EP_TYPE_CTRL: Control type
+ * @arg EP_TYPE_ISOC: Isochrounous type
+ * @arg EP_TYPE_BULK: Bulk type
+ * @arg EP_TYPE_INTR: Interrupt type
+ * @param token : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg 0: PID_SETUP
+ * @arg 1: PID_DATA
+ * @param pbuff : pointer to URB data
+ * @param length : Length of URB data
+ * @param do_ping : activate do ping protocol (for high speed only)
+ * This parameter can be one of the these values:
+ * 0 : do ping inactive
+ * 1 : do ping active
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t direction ,
+ uint8_t ep_type,
+ uint8_t token,
+ uint8_t* pbuff,
+ uint16_t length,
+ uint8_t do_ping )
+{
+ HAL_HCD_HC_SubmitRequest (phost->pData,
+ pipe,
+ direction ,
+ ep_type,
+ token,
+ pbuff,
+ length,
+ do_ping);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetURBState
+ * Get a URB state from the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @retval URB state
+ * This parameter can be one of the these values:
+ * @arg URB_IDLE
+ * @arg URB_DONE
+ * @arg URB_NOTREADY
+ * @arg URB_NYET
+ * @arg URB_ERROR
+ * @arg URB_STALL
+ */
+USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return (USBH_URBStateTypeDef)HAL_HCD_HC_GetURBState (phost->pData, pipe);
+}
+
+/**
+ * @brief USBH_LL_DriverVBUS
+ * Drive VBUS.
+ * @param phost: Host handle
+ * @param state : VBUS state
+ * This parameter can be one of the these values:
+ * 0 : VBUS Active
+ * 1 : VBUS Inactive
+ * @retval Status
+ */
+USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t state)
+{
+ //Our VBUS is permanently on, so don't bother with this...
+
+// if (phost->id == HOST_FS)
+// {
+// if(state == 0)
+// {
+// //VBUS off
+// }
+// else
+// {
+// //VBUS on
+// }
+// }
+// HAL_Delay(200);
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SetToggle
+ * Set toggle for a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @param pipe_num: Pipe index
+ * @param toggle: toggle (0/1)
+ * @retval Status
+ */
+USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
+{
+ HCD_HandleTypeDef *pHandle;
+ pHandle = phost->pData;
+
+ if(pHandle->hc[pipe].ep_is_in)
+ {
+ pHandle->hc[pipe].toggle_in = toggle;
+ }
+ else
+ {
+ pHandle->hc[pipe].toggle_out = toggle;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetToggle
+ * Return the current toggle of a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval toggle (0/1)
+ */
+uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ uint8_t toggle = 0;
+ HCD_HandleTypeDef *pHandle;
+ pHandle = phost->pData;
+
+ if(pHandle->hc[pipe].ep_is_in)
+ {
+ toggle = pHandle->hc[pipe].toggle_in;
+ }
+ else
+ {
+ toggle = pHandle->hc[pipe].toggle_out;
+ }
+ return toggle;
+}
+
+/**
+ * @brief USBH_Delay
+ * Delay routine for the USB Host Library
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBH_Delay (uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Downstream/gcc_arm_stm32f401.ld b/Downstream/gcc_arm_stm32f401.ld
new file mode 100644
index 0000000..0fffc55
--- /dev/null
+++ b/Downstream/gcc_arm_stm32f401.ld
@@ -0,0 +1,115 @@
+/* Linker script to configure memory regions. */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ SRAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
+
+}
+
+/* Library configurations */
+GROUP(libgcc.a libc.a libm.a libnosys.a)
+
+/* Linker script to place sections and symbol values. Should be used together
+ * with other linker script that defines memory regions FLASH and RAM.
+ * It references following symbols, which must be defined in code:
+ * Reset_Handler : Entry of reset handler
+ *
+ * It defines following symbols, which code can use without definition:
+ * __exidx_start
+ * __exidx_end
+ * __copy_table_start__
+ * __copy_table_end__
+ * __zero_table_start__
+ * __zero_table_end__
+ * __etext
+ * __data_start__
+ * __preinit_array_start
+ * __preinit_array_end
+ * __init_array_start
+ * __init_array_end
+ * __fini_array_start
+ * __fini_array_end
+ * __data_end__
+ * __bss_start__
+ * __bss_end__
+ * __end__
+ * end
+ * __HeapLimit
+ * __StackLimit
+ * __StackTop
+ * __stack
+ * __Vectors_End
+ * __Vectors_Size
+ */
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+ .text :
+ {
+ KEEP(*(.vectors))
+ __Vectors_End = .;
+ __Vectors_Size = __Vectors_End - __Vectors;
+ __end__ = .;
+
+ *(.text*)
+
+ KEEP(*(.init))
+ KEEP(*(.fini))
+
+
+ *(.rodata*)
+
+ KEEP(*(.eh_frame*))
+ } > FLASH
+
+ __etext = .;
+
+ .data : AT (__etext)
+ {
+ __data_start__ = .;
+ *(vtable)
+ *(.data*)
+
+ /* All data end */
+ __data_end__ = .;
+
+ } > SRAM1
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > SRAM1
+
+ .heap (COPY):
+ {
+ __HeapBase = .;
+ __end__ = .;
+ end = __end__;
+ KEEP(*(.heap*))
+ __HeapLimit = .;
+ } > SRAM1
+
+ /* .stack_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later */
+ .stack_dummy (COPY):
+ {
+ KEEP(*(.stack*))
+ } > SRAM1
+
+ /* Set stack top to end of RAM, and stack limit move down by
+ * size of stack_dummy section */
+ __StackTop = ORIGIN(SRAM1) + LENGTH(SRAM1);
+ __StackLimit = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
+
+}