From 8cfa2e802332957d461dadfca156a847cf8f0cc3 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Sat, 6 Jul 2013 12:26:33 +0200 Subject: [PATCH] Add automatic application start on virtual disk ejection to the Mass Storage class bootloader. --- .../MassStorage/BootloaderMassStorage.c | 47 ++++++++++++++++++- .../MassStorage/BootloaderMassStorage.h | 13 ++++- .../MassStorage/BootloaderMassStorage.txt | 12 +++-- Bootloaders/MassStorage/Config/AppConfig.h | 47 +++++++++++++++++++ Bootloaders/MassStorage/Lib/SCSI.c | 6 ++- Bootloaders/MassStorage/Lib/SCSI.h | 1 + LUFA/Build/lufa_core.mk | 2 +- 7 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 Bootloaders/MassStorage/Config/AppConfig.h diff --git a/Bootloaders/MassStorage/BootloaderMassStorage.c b/Bootloaders/MassStorage/BootloaderMassStorage.c index 28f42b6d20..1b6eda4387 100644 --- a/Bootloaders/MassStorage/BootloaderMassStorage.c +++ b/Bootloaders/MassStorage/BootloaderMassStorage.c @@ -33,6 +33,7 @@ * Main source file for the Mass Storage class bootloader. This file contains the complete bootloader logic. */ +#define INCLUDE_FROM_BOOTLOADER_MASSSTORAGE_C #include "BootloaderMassStorage.h" /** LUFA Mass Storage Class driver interface configuration and state information. This structure is @@ -60,7 +61,30 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface = }, }; +/** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run + * via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application + * started via a forced watchdog reset. + */ +bool RunBootloader = true; + +/** Magic lock for forced application start. If the HWBE fuse is programmed and BOOTRST is unprogrammed, the bootloader + * will start if the /HWB line of the AVR is held low and the system is reset. However, if the /HWB line is still held + * low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value + * \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start. + */ +uint16_t MagicBootKey ATTR_NO_INIT; + +/** Indicates if the bootloader is allowed to exit immediately if \ref RunBootloader is \c false. During shutdown all + * pending commands must be processed before jumping to the user-application, thus this tracks the main program loop + * iterations since a SCSI command from the host was received. + */ +static uint8_t TicksSinceLastCommand = 0; + +/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application + * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, + * this will force the user application to start via a software jump. + */ void Application_Jump_Check(void) { bool JumpToApplication = false; @@ -90,6 +114,13 @@ void Application_Jump_Check(void) JTAG_ENABLE(); #endif + /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ + if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) + { + MagicBootKey = 0; + JumpToApplication = true; + } + if (JumpToApplication) { // cppcheck-suppress constStatement @@ -107,11 +138,22 @@ int main(void) LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); GlobalInterruptEnable(); - for (;;) + while (RunBootloader || TicksSinceLastCommand++ < 0xFF) { MS_Device_USBTask(&Disk_MS_Interface); USB_USBTask(); } + + /* Disconnect from the host - USB interface will be reset later along with the AVR */ + USB_Detach(); + + /* Unlock the forced application start mode of the bootloader if it is restarted */ + MagicBootKey = MAGIC_BOOT_KEY; + + /* Enable the watchdog and force a timeout to reset the AVR */ + wdt_enable(WDTO_250MS); + + for (;;); } /** Configures the board hardware and chip peripherals for the demo's functionality. */ @@ -189,5 +231,8 @@ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSI CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo); LEDs_SetAllLEDs(LEDMASK_USB_READY); + /* Signal that a command was processed, must not exit bootloader yet */ + TicksSinceLastCommand = 0; + return CommandSuccess; } diff --git a/Bootloaders/MassStorage/BootloaderMassStorage.h b/Bootloaders/MassStorage/BootloaderMassStorage.h index 1fcce9063c..d8271ea54f 100644 --- a/Bootloaders/MassStorage/BootloaderMassStorage.h +++ b/Bootloaders/MassStorage/BootloaderMassStorage.h @@ -44,6 +44,7 @@ #include #include "Descriptors.h" + #include "Config/AppConfig.h" #include "Lib/SCSI.h" @@ -72,11 +73,15 @@ /** LED mask for the library LED driver, to indicate that the USB interface is busy. */ #define LEDMASK_USB_BUSY LEDS_LED2 + /** Magic bootloader key to unlock forced application start mode. */ + #define MAGIC_BOOT_KEY 0xDC42 + + /* Global Variables: */ + extern bool RunBootloader; + /* Function Prototypes: */ int main(void) AUX_BOOT_SECTION; - static void SetupHardware(void) AUX_BOOT_SECTION; - void Application_Jump_Check(void) ATTR_INIT_SECTION(3); void EVENT_USB_Device_Connect(void) AUX_BOOT_SECTION; @@ -86,5 +91,9 @@ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION; + #if defined(INCLUDE_FROM_BOOTLOADER_MASSSTORAGE_C) + static void SetupHardware(void) AUX_BOOT_SECTION; + #endif + #endif diff --git a/Bootloaders/MassStorage/BootloaderMassStorage.txt b/Bootloaders/MassStorage/BootloaderMassStorage.txt index 85cbc6f63b..f7b303858d 100644 --- a/Bootloaders/MassStorage/BootloaderMassStorage.txt +++ b/Bootloaders/MassStorage/BootloaderMassStorage.txt @@ -191,9 +191,15 @@ * * * - * + * + * + * + * + * + * + * + * * *
- * None - * Define Name:Location:Description:
NO_APP_START_ON_EJECTAppConfig.hDefine to disable automatic start of the loaded application when the virtual + * Mass Storage disk is ejected on the host.
*/ diff --git a/Bootloaders/MassStorage/Config/AppConfig.h b/Bootloaders/MassStorage/Config/AppConfig.h new file mode 100644 index 0000000000..ada237153a --- /dev/null +++ b/Bootloaders/MassStorage/Config/AppConfig.h @@ -0,0 +1,47 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2013. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2013 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief Application Configuration Header File + * + * This is a header file which is be used to configure LUFA's + * compile time options, as an alternative to the compile time + * constants supplied through a makefile. + * + * For information on what each token does, refer to the + * \ref Sec_Options section of the application documentation. + */ + +#ifndef _APP_CONFIG_H_ +#define _APP_CONFIG_H_ + +// #define NO_APP_START_ON_EJECT + +#endif diff --git a/Bootloaders/MassStorage/Lib/SCSI.c b/Bootloaders/MassStorage/Lib/SCSI.c index eeb2c252a2..3bb868ccca 100644 --- a/Bootloaders/MassStorage/Lib/SCSI.c +++ b/Bootloaders/MassStorage/Lib/SCSI.c @@ -113,8 +113,12 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) case SCSI_CMD_MODE_SENSE_6: CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo); break; - case SCSI_CMD_SEND_DIAGNOSTIC: case SCSI_CMD_START_STOP_UNIT: +#if !defined(NO_APP_START_ON_EJECT) + /* If the user ejected the volume, signal bootloader exit at next opportunity. */ + RunBootloader = ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[4] & 0x03) != 0x02); +#endif + case SCSI_CMD_SEND_DIAGNOSTIC: case SCSI_CMD_TEST_UNIT_READY: case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: case SCSI_CMD_VERIFY_10: diff --git a/Bootloaders/MassStorage/Lib/SCSI.h b/Bootloaders/MassStorage/Lib/SCSI.h index 8eb817fa77..afed5a664d 100644 --- a/Bootloaders/MassStorage/Lib/SCSI.h +++ b/Bootloaders/MassStorage/Lib/SCSI.h @@ -42,6 +42,7 @@ #include + #include "../BootloaderMassStorage.h" #include "../Descriptors.h" #include "VirtualFAT.h" diff --git a/LUFA/Build/lufa_core.mk b/LUFA/Build/lufa_core.mk index 914a939ccb..11bf65ca9a 100644 --- a/LUFA/Build/lufa_core.mk +++ b/LUFA/Build/lufa_core.mk @@ -131,7 +131,7 @@ help: @printf " %b" "$(PRINTABLE_LUFA_PROVIDED_MACROS:%= - %\n)" @echo " " @echo "===================================================================" - @echo " The LUFA BuildSystem 2.0 - Powered By Duct Tape (tm) " + @echo " The LUFA BuildSystem 2.0 - Powered By Positive Thinking (tm) " @echo "===================================================================" # Lists build modules included by the project makefile, in alphabetical order