aboutsummaryrefslogtreecommitdiffstats
path: root/Projects
diff options
context:
space:
mode:
authorDean Camera <dean@fourwalledcubicle.com>2010-01-28 12:47:35 +0000
committerDean Camera <dean@fourwalledcubicle.com>2010-01-28 12:47:35 +0000
commitd11ed10c5314c44dc01c06954d1d73d4894cbff8 (patch)
treefb771919dd20943a820f37d62a9488e32d07950a /Projects
parentd26a9ed5fd6fc60a0dfa61d04f5ae2bd7163a85d (diff)
downloadlufa-d11ed10c5314c44dc01c06954d1d73d4894cbff8.tar.gz
lufa-d11ed10c5314c44dc01c06954d1d73d4894cbff8.tar.bz2
lufa-d11ed10c5314c44dc01c06954d1d73d4894cbff8.zip
Add FatFS library to the Webserver project, extend the HTTP server so that it now serves files from the Dataflash. Add Mass Storage device mode class driver so that files can be loaded to the board Dataflash when inserted into a PC.
Diffstat (limited to 'Projects')
-rw-r--r--Projects/TemperatureDataLogger/makefile2
-rw-r--r--Projects/Webserver/Descriptors.c217
-rw-r--r--Projects/Webserver/Descriptors.h72
-rw-r--r--Projects/Webserver/Lib/DataflashManager.c525
-rw-r--r--Projects/Webserver/Lib/DataflashManager.h80
-rw-r--r--Projects/Webserver/Lib/FATFs/00readme.txt110
-rw-r--r--Projects/Webserver/Lib/FATFs/diskio.c92
-rw-r--r--Projects/Webserver/Lib/FATFs/diskio.h72
-rw-r--r--Projects/Webserver/Lib/FATFs/diskio.lst149
-rw-r--r--Projects/Webserver/Lib/FATFs/ff.c3153
-rw-r--r--Projects/Webserver/Lib/FATFs/ff.h596
-rw-r--r--Projects/Webserver/Lib/FATFs/ff.lst3062
-rw-r--r--Projects/Webserver/Lib/FATFs/ffconf.h166
-rw-r--r--Projects/Webserver/Lib/FATFs/integer.h37
-rw-r--r--Projects/Webserver/Lib/HTTPServerApp.c177
-rw-r--r--Projects/Webserver/Lib/HTTPServerApp.h (renamed from Projects/Webserver/Lib/WebserverApp.h)10
-rw-r--r--Projects/Webserver/Lib/SCSI.c281
-rw-r--r--Projects/Webserver/Lib/SCSI.h85
-rw-r--r--Projects/Webserver/Lib/WebserverApp.c142
-rw-r--r--Projects/Webserver/Lib/uIPManagement.c189
-rw-r--r--Projects/Webserver/Lib/uIPManagement.h73
-rw-r--r--Projects/Webserver/Lib/uip/conf/apps-conf.h5
-rw-r--r--Projects/Webserver/USBDeviceMode.c113
-rw-r--r--Projects/Webserver/USBDeviceMode.h56
-rw-r--r--Projects/Webserver/USBHostMode.c178
-rw-r--r--Projects/Webserver/USBHostMode.h57
-rw-r--r--Projects/Webserver/Webserver.c267
-rw-r--r--Projects/Webserver/Webserver.h35
-rw-r--r--Projects/Webserver/Webserver.txt28
-rw-r--r--Projects/Webserver/makefile37
30 files changed, 9602 insertions, 464 deletions
diff --git a/Projects/TemperatureDataLogger/makefile b/Projects/TemperatureDataLogger/makefile
index 990156f26..a3da35ff3 100644
--- a/Projects/TemperatureDataLogger/makefile
+++ b/Projects/TemperatureDataLogger/makefile
@@ -128,9 +128,9 @@ SRC = $(TARGET).c \
Descriptors.c \
Lib/DataflashManager.c \
Lib/SCSI.c \
+ Lib/DS1307.c \
Lib/FATFs/diskio.c \
Lib/FATFs/ff.c \
- Lib/DS1307.c \
$(LUFA_PATH)/LUFA/Drivers/Board/Temperature.c \
$(LUFA_PATH)/LUFA/Drivers/Peripheral/TWI.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
diff --git a/Projects/Webserver/Descriptors.c b/Projects/Webserver/Descriptors.c
new file mode 100644
index 000000000..40ce620a6
--- /dev/null
+++ b/Projects/Webserver/Descriptors.c
@@ -0,0 +1,217 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * USB Device Descriptors, for library use when in USB device mode. Descriptors are special
+ * computer-readable structures which the host requests upon device enumeration, to determine
+ * the device's capabilities and functions.
+ */
+
+#include "Descriptors.h"
+
+/* On some devices, there is a factory set internal serial number which can be automatically sent to the host as
+ * the device's serial number when the Device Descriptor's .SerialNumStrIndex entry is set to USE_INTERNAL_SERIAL.
+ * This allows the host to track a device across insertions on different ports, allowing them to retain allocated
+ * resources like COM port numbers and drivers. On demos using this feature, give a warning on unsupported devices
+ * so that the user can supply their own serial number descriptor instead or remove the USE_INTERNAL_SERIAL value
+ * from the Device Descriptor (forcing the host to generate a serial number for each device from the VID, PID and
+ * port location).
+ */
+#if (USE_INTERNAL_SERIAL == NO_DESCRIPTOR)
+ #warning USE_INTERNAL_SERIAL is not available on this AVR - please manually construct a device serial descriptor.
+#endif
+
+/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
+ * device characteristics, including the supported USB version, control endpoint size and the
+ * number of device configurations. The descriptor is read out by the USB host when the enumeration
+ * process begins.
+ */
+USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
+{
+ .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
+
+ .USBSpecification = VERSION_BCD(01.10),
+ .Class = 0x00,
+ .SubClass = 0x00,
+ .Protocol = 0x00,
+
+ .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
+
+ .VendorID = 0x03EB,
+ .ProductID = 0x2045,
+ .ReleaseNumber = 0x0000,
+
+ .ManufacturerStrIndex = 0x01,
+ .ProductStrIndex = 0x02,
+ .SerialNumStrIndex = USE_INTERNAL_SERIAL,
+
+ .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
+};
+
+/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
+ * of the device in one of its supported configurations, including information about any device interfaces
+ * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
+ * a configuration so that the host may correctly communicate with the USB device.
+ */
+USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
+{
+ .Config =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
+
+ .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
+ .TotalInterfaces = 1,
+
+ .ConfigurationNumber = 1,
+ .ConfigurationStrIndex = NO_DESCRIPTOR,
+
+ .ConfigAttributes = USB_CONFIG_ATTR_BUSPOWERED,
+
+ .MaxPowerConsumption = USB_CONFIG_POWER_MA(100)
+ },
+
+ .Interface =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
+
+ .InterfaceNumber = 0,
+ .AlternateSetting = 0,
+
+ .TotalEndpoints = 2,
+
+ .Class = 0x08,
+ .SubClass = 0x06,
+ .Protocol = 0x50,
+
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+
+ .DataInEndpoint =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+ .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MASS_STORAGE_IN_EPNUM),
+ .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = MASS_STORAGE_IO_EPSIZE,
+ .PollingIntervalMS = 0x00
+ },
+
+ .DataOutEndpoint =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+ .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MASS_STORAGE_OUT_EPNUM),
+ .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = MASS_STORAGE_IO_EPSIZE,
+ .PollingIntervalMS = 0x00
+ }
+};
+
+/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
+ * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
+ * via the language ID table available at USB.org what languages the device supports for its string descriptors.
+ */
+USB_Descriptor_String_t PROGMEM LanguageString =
+{
+ .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
+
+ .UnicodeString = {LANGUAGE_ID_ENG}
+};
+
+/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
+ * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
+ * Descriptor.
+ */
+USB_Descriptor_String_t PROGMEM ManufacturerString =
+{
+ .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String},
+
+ .UnicodeString = L"Dean Camera"
+};
+
+/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
+ * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
+ * Descriptor.
+ */
+USB_Descriptor_String_t PROGMEM ProductString =
+{
+ .Header = {.Size = USB_STRING_LEN(22), .Type = DTYPE_String},
+
+ .UnicodeString = L"LUFA Mass Storage Demo"
+};
+
+/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
+ * documentation) by the application code so that the address and size of a requested descriptor can be given
+ * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
+ * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
+ * USB host.
+ */
+uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress)
+{
+ const uint8_t DescriptorType = (wValue >> 8);
+ const uint8_t DescriptorNumber = (wValue & 0xFF);
+
+ void* Address = NULL;
+ uint16_t Size = NO_DESCRIPTOR;
+
+ switch (DescriptorType)
+ {
+ case DTYPE_Device:
+ Address = (void*)&DeviceDescriptor;
+ Size = sizeof(USB_Descriptor_Device_t);
+ break;
+ case DTYPE_Configuration:
+ Address = (void*)&ConfigurationDescriptor;
+ Size = sizeof(USB_Descriptor_Configuration_t);
+ break;
+ case DTYPE_String:
+ switch (DescriptorNumber)
+ {
+ case 0x00:
+ Address = (void*)&LanguageString;
+ Size = pgm_read_byte(&LanguageString.Header.Size);
+ break;
+ case 0x01:
+ Address = (void*)&ManufacturerString;
+ Size = pgm_read_byte(&ManufacturerString.Header.Size);
+ break;
+ case 0x02:
+ Address = (void*)&ProductString;
+ Size = pgm_read_byte(&ProductString.Header.Size);
+ break;
+ }
+
+ break;
+ }
+
+ *DescriptorAddress = Address;
+ return Size;
+}
diff --git a/Projects/Webserver/Descriptors.h b/Projects/Webserver/Descriptors.h
new file mode 100644
index 000000000..dcaaddaf7
--- /dev/null
+++ b/Projects/Webserver/Descriptors.h
@@ -0,0 +1,72 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for Descriptors.c.
+ */
+
+#ifndef _DESCRIPTORS_H_
+#define _DESCRIPTORS_H_
+
+ /* Includes: */
+ #include <avr/pgmspace.h>
+
+ #include <LUFA/Drivers/USB/USB.h>
+ #include <LUFA/Drivers/USB/Class/MassStorage.h>
+
+ /* Macros: */
+ /** Endpoint number of the Mass Storage device-to-host data IN endpoint. */
+ #define MASS_STORAGE_IN_EPNUM 3
+
+ /** Endpoint number of the Mass Storage host-to-device data OUT endpoint. */
+ #define MASS_STORAGE_OUT_EPNUM 4
+
+ /** Size in bytes of the Mass Storage data endpoints. */
+ #define MASS_STORAGE_IO_EPSIZE 64
+
+ /* Type Defines: */
+ /** Type define for the device configuration descriptor structure. This must be defined in the
+ * application code, as the configuration descriptor contains several sub-descriptors which
+ * vary between devices, and which describe the device's usage to the host.
+ */
+ typedef struct
+ {
+ USB_Descriptor_Configuration_Header_t Config;
+ USB_Descriptor_Interface_t Interface;
+ USB_Descriptor_Endpoint_t DataInEndpoint;
+ USB_Descriptor_Endpoint_t DataOutEndpoint;
+ } USB_Descriptor_Configuration_t;
+
+ /* Function Prototypes: */
+ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress)
+ ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
+
+#endif
diff --git a/Projects/Webserver/Lib/DataflashManager.c b/Projects/Webserver/Lib/DataflashManager.c
new file mode 100644
index 000000000..1de866ede
--- /dev/null
+++ b/Projects/Webserver/Lib/DataflashManager.c
@@ -0,0 +1,525 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Functions to manage the physical dataflash media, including reading and writing of
+ * blocks of data. These functions are called by the SCSI layer when data must be stored
+ * or retrieved to/from the physical storage media. If a different media is used (such
+ * as a SD card or EEPROM), functions similar to these will need to be generated.
+ */
+
+#define INCLUDE_FROM_DATAFLASHMANAGER_C
+#include "DataflashManager.h"
+
+/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
+ * the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
+ * them to the dataflash in Dataflash page sized blocks.
+ *
+ * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
+ * \param[in] BlockAddress Data block starting address for the write sequence
+ * \param[in] TotalBlocks Number of blocks of data to write
+ */
+void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
+{
+ uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
+ uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
+ uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
+ bool UsingSecondBuffer = false;
+
+ /* Select the correct starting Dataflash IC for the block requested */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
+ /* Copy selected dataflash's current page contents to the dataflash buffer */
+ Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_WaitWhileBusy();
+#endif
+
+ /* Send the dataflash buffer write command */
+ Dataflash_SendByte(DF_CMD_BUFF1WRITE);
+ Dataflash_SendAddressBytes(0, CurrDFPageByte);
+
+ /* Wait until endpoint is ready before continuing */
+ if (Endpoint_WaitUntilReady())
+ return;
+
+ while (TotalBlocks)
+ {
+ uint8_t BytesInBlockDiv16 = 0;
+
+ /* Write an endpoint packet sized data block to the dataflash */
+ while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
+ {
+ /* Check if the endpoint is currently empty */
+ if (!(Endpoint_IsReadWriteAllowed()))
+ {
+ /* Clear the current endpoint bank */
+ Endpoint_ClearOUT();
+
+ /* Wait until the host has sent another packet */
+ if (Endpoint_WaitUntilReady())
+ return;
+ }
+
+ /* Check if end of dataflash page reached */
+ if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Write the dataflash buffer contents back to the dataflash page */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+
+ /* Reset the dataflash buffer counter, increment the page counter */
+ CurrDFPageByteDiv16 = 0;
+ CurrDFPage++;
+
+ /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
+ if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
+ UsingSecondBuffer = !(UsingSecondBuffer);
+
+ /* Select the next dataflash chip based on the new dataflash page index */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
+ /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
+ if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Copy selected dataflash's current page contents to the dataflash buffer */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_WaitWhileBusy();
+ }
+#endif
+
+ /* Send the dataflash buffer write command */
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
+ Dataflash_SendAddressBytes(0, 0);
+ }
+
+ /* Write one 16-byte chunk of data to the dataflash */
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+ Dataflash_SendByte(Endpoint_Read_Byte());
+
+ /* Increment the dataflash page 16 byte block counter */
+ CurrDFPageByteDiv16++;
+
+ /* Increment the block 16 byte block counter */
+ BytesInBlockDiv16++;
+
+ /* Check if the current command is being aborted by the host */
+ if (MSInterfaceInfo->State.IsMassStoreReset)
+ return;
+ }
+
+ /* Decrement the blocks remaining counter and reset the sub block counter */
+ TotalBlocks--;
+ }
+
+ /* Write the dataflash buffer contents back to the dataflash page */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
+ Dataflash_SendAddressBytes(CurrDFPage, 0x00);
+ Dataflash_WaitWhileBusy();
+
+ /* If the endpoint is empty, clear it ready for the next packet from the host */
+ if (!(Endpoint_IsReadWriteAllowed()))
+ Endpoint_ClearOUT();
+
+ /* Deselect all dataflash chips */
+ Dataflash_DeselectChip();
+}
+
+/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
+ * the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
+ * and writes them in OS sized blocks to the endpoint.
+ *
+ * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
+ * \param[in] BlockAddress Data block starting address for the read sequence
+ * \param[in] TotalBlocks Number of blocks of data to read
+ */
+void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
+{
+ uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
+ uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
+ uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
+
+ /* Select the correct starting Dataflash IC for the block requested */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+ /* Send the dataflash main memory page read command */
+ Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
+ Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+
+ /* Wait until endpoint is ready before continuing */
+ if (Endpoint_WaitUntilReady())
+ return;
+
+ while (TotalBlocks)
+ {
+ uint8_t BytesInBlockDiv16 = 0;
+
+ /* Write an endpoint packet sized data block to the dataflash */
+ while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
+ {
+ /* Check if the endpoint is currently full */
+ if (!(Endpoint_IsReadWriteAllowed()))
+ {
+ /* Clear the endpoint bank to send its contents to the host */
+ Endpoint_ClearIN();
+
+ /* Wait until the endpoint is ready for more data */
+ if (Endpoint_WaitUntilReady())
+ return;
+ }
+
+ /* Check if end of dataflash page reached */
+ if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Reset the dataflash buffer counter, increment the page counter */
+ CurrDFPageByteDiv16 = 0;
+ CurrDFPage++;
+
+ /* Select the next dataflash chip based on the new dataflash page index */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+ /* Send the dataflash main memory page read command */
+ Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ }
+
+ /* Read one 16-byte chunk of data from the dataflash */
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+ Endpoint_Write_Byte(Dataflash_ReceiveByte());
+
+ /* Increment the dataflash page 16 byte block counter */
+ CurrDFPageByteDiv16++;
+
+ /* Increment the block 16 byte block counter */
+ BytesInBlockDiv16++;
+
+ /* Check if the current command is being aborted by the host */
+ if (MSInterfaceInfo->State.IsMassStoreReset)
+ return;
+ }
+
+ /* Decrement the blocks remaining counter */
+ TotalBlocks--;
+ }
+
+ /* If the endpoint is full, send its contents to the host */
+ if (!(Endpoint_IsReadWriteAllowed()))
+ Endpoint_ClearIN();
+
+ /* Deselect all dataflash chips */
+ Dataflash_DeselectChip();
+}
+
+/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
+ * the a given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
+ * dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
+ * dataflash.
+ *
+ * \param[in] BlockAddress Data block starting address for the write sequence
+ * \param[in] TotalBlocks Number of blocks of data to write
+ * \param[in] BufferPtr Pointer to the data source RAM buffer
+ */
+void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, const uint8_t* BufferPtr)
+{
+ uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
+ uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
+ uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
+ bool UsingSecondBuffer = false;
+
+ /* Select the correct starting Dataflash IC for the block requested */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
+ /* Copy selected dataflash's current page contents to the dataflash buffer */
+ Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_WaitWhileBusy();
+#endif
+
+ /* Send the dataflash buffer write command */
+ Dataflash_SendByte(DF_CMD_BUFF1WRITE);
+ Dataflash_SendAddressBytes(0, CurrDFPageByte);
+
+ while (TotalBlocks)
+ {
+ uint8_t BytesInBlockDiv16 = 0;
+
+ /* Write an endpoint packet sized data block to the dataflash */
+ while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
+ {
+ /* Check if end of dataflash page reached */
+ if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Write the dataflash buffer contents back to the dataflash page */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+
+ /* Reset the dataflash buffer counter, increment the page counter */
+ CurrDFPageByteDiv16 = 0;
+ CurrDFPage++;
+
+ /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
+ if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
+ UsingSecondBuffer = !(UsingSecondBuffer);
+
+ /* Select the next dataflash chip based on the new dataflash page index */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
+ /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
+ if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Copy selected dataflash's current page contents to the dataflash buffer */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_WaitWhileBusy();
+ }
+#endif
+
+ /* Send the dataflash buffer write command */
+ Dataflash_ToggleSelectedChipCS();
+ Dataflash_SendByte(DF_CMD_BUFF1WRITE);
+ Dataflash_SendAddressBytes(0, 0);
+ }
+
+ /* Write one 16-byte chunk of data to the dataflash */
+ for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
+ Dataflash_SendByte(*(BufferPtr++));
+
+ /* Increment the dataflash page 16 byte block counter */
+ CurrDFPageByteDiv16++;
+
+ /* Increment the block 16 byte block counter */
+ BytesInBlockDiv16++;
+ }
+
+ /* Decrement the blocks remaining counter and reset the sub block counter */
+ TotalBlocks--;
+ }
+
+ /* Write the dataflash buffer contents back to the dataflash page */
+ Dataflash_WaitWhileBusy();
+ Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
+ Dataflash_SendAddressBytes(CurrDFPage, 0x00);
+ Dataflash_WaitWhileBusy();
+
+ /* Deselect all dataflash chips */
+ Dataflash_DeselectChip();
+}
+
+/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
+ * the a preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
+ * and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
+ * the files stored on the dataflash.
+ *
+ * \param[in] BlockAddress Data block starting address for the read sequence
+ * \param[in] TotalBlocks Number of blocks of data to read
+ * \param[out] BufferPtr Pointer to the data destination RAM buffer
+ */
+void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
+{
+ uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
+ uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
+ uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
+
+ /* Select the correct starting Dataflash IC for the block requested */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+ /* Send the dataflash main memory page read command */
+ Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
+ Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+
+ while (TotalBlocks)
+ {
+ uint8_t BytesInBlockDiv16 = 0;
+
+ /* Write an endpoint packet sized data block to the dataflash */
+ while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
+ {
+ /* Check if end of dataflash page reached */
+ if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
+ {
+ /* Reset the dataflash buffer counter, increment the page counter */
+ CurrDFPageByteDiv16 = 0;
+ CurrDFPage++;
+
+ /* Select the next dataflash chip based on the new dataflash page index */
+ Dataflash_SelectChipFromPage(CurrDFPage);
+
+ /* Send the dataflash main memory page read command */
+ Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
+ Dataflash_SendAddressBytes(CurrDFPage, 0);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ Dataflash_SendByte(0x00);
+ }
+
+ /* Read one 16-byte chunk of data from the dataflash */
+ for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
+ *(BufferPtr++) = Dataflash_ReceiveByte();
+
+ /* Increment the dataflash page 16 byte block counter */
+ CurrDFPageByteDiv16++;
+
+ /* Increment the block 16 byte block counter */
+ BytesInBlockDiv16++;
+ }
+
+ /* Decrement the blocks remaining counter */
+ TotalBlocks--;
+ }
+
+ /* Deselect all dataflash chips */
+ Dataflash_DeselectChip();
+}
+
+/** Disables the dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
+void DataflashManager_ResetDataflashProtections(void)
+{
+ /* Select first dataflash chip, send the read status register command */
+ Dataflash_SelectChip(DATAFLASH_CHIP1);
+ Dataflash_SendByte(DF_CMD_GETSTATUS);
+
+ /* Check if sector protection is enabled */
+ if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
+ {
+ Dataflash_ToggleSelectedChipCS();
+
+ /* Send the commands to disable sector protection */
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
+ }
+
+ /* Select second dataflash chip (if present on selected board), send read status register command */
+ #if (DATAFLASH_TOTALCHIPS == 2)
+ Dataflash_SelectChip(DATAFLASH_CHIP2);
+ Dataflash_SendByte(DF_CMD_GETSTATUS);
+
+ /* Check if sector protection is enabled */
+ if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
+ {
+ Dataflash_ToggleSelectedChipCS();
+
+ /* Send the commands to disable sector protection */
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
+ Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
+ }
+ #endif
+
+ /* Deselect current dataflash chip */
+ Dataflash_DeselectChip();
+}
+
+/** Performs a simple test on the attached Dataflash IC(s) to ensure that they are working.
+ *
+ * \return Boolean true if all media chips are working, false otherwise
+ */
+bool DataflashManager_CheckDataflashOperation(void)
+{
+ uint8_t ReturnByte;
+
+ /* Test first Dataflash IC is present and responding to commands */
+ Dataflash_SelectChip(DATAFLASH_CHIP1);
+ Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
+ ReturnByte = Dataflash_ReceiveByte();
+ Dataflash_DeselectChip();
+
+ /* If returned data is invalid, fail the command */
+ if (ReturnByte != DF_MANUFACTURER_ATMEL)
+ return false;
+
+ #if (DATAFLASH_TOTALCHIPS == 2)
+ /* Test second Dataflash IC is present and responding to commands */
+ Dataflash_SelectChip(DATAFLASH_CHIP2);
+ Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
+ ReturnByte = Dataflash_ReceiveByte();
+ Dataflash_DeselectChip();
+
+ /* If returned data is invalid, fail the command */
+ if (ReturnByte != DF_MANUFACTURER_ATMEL)
+ return false;
+ #endif
+
+ return true;
+}
diff --git a/Projects/Webserver/Lib/DataflashManager.h b/Projects/Webserver/Lib/DataflashManager.h
new file mode 100644
index 000000000..d3ea0ff50
--- /dev/null
+++ b/Projects/Webserver/Lib/DataflashManager.h
@@ -0,0 +1,80 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for DataflashManager.c.
+ */
+
+#ifndef _DATAFLASH_MANAGER_H
+#define _DATAFLASH_MANAGER_H
+
+ /* Includes: */
+ #include <avr/io.h>
+
+ #include "Descriptors.h"
+
+ #include <LUFA/Common/Common.h>
+ #include <LUFA/Drivers/USB/USB.h>
+ #include <LUFA/Drivers/USB/Class/MassStorage.h>
+ #include <LUFA/Drivers/Board/Dataflash.h>
+
+ /* Preprocessor Checks: */
+ #if (DATAFLASH_PAGE_SIZE % 16)
+ #error Dataflash page size must be a multiple of 16 bytes.
+ #endif
+
+ /* Defines: */
+ /** Total number of bytes of the storage medium, comprised of one or more dataflash ICs. */
+ #define VIRTUAL_MEMORY_BYTES ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
+
+ /** Block size of the device. This is kept at 512 to remain compatible with the OS despite the underlying
+ * storage media (Dataflash) using a different native block size. Do not change this value.
+ */
+ #define VIRTUAL_MEMORY_BLOCK_SIZE 512
+
+ /** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. Do not
+ * change this value; change VIRTUAL_MEMORY_BYTES instead to alter the media size.
+ */
+ #define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
+
+ /* Function Prototypes: */
+ void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
+ uint16_t TotalBlocks);
+ void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
+ uint16_t TotalBlocks);
+ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,
+ const uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
+ void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,
+ uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
+ void DataflashManager_ResetDataflashProtections(void);
+ bool DataflashManager_CheckDataflashOperation(void);
+
+#endif
diff --git a/Projects/Webserver/Lib/FATFs/00readme.txt b/Projects/Webserver/Lib/FATFs/00readme.txt
new file mode 100644
index 000000000..295be3b9a
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/00readme.txt
@@ -0,0 +1,110 @@
+FatFs Module Source Files R0.07e (C)ChaN, 2010
+
+
+FILES
+
+ ffconf.h Configuration file for FatFs module.
+ ff.h Common include file for FatFs and application module.
+ ff.c FatFs module.
+ diskio.h Common include file for FatFs and disk I/O module.
+ diskio.c Skeleton of low level disk I/O module.
+ integer.h Alternative type definitions for integer variables.
+ option Optional external functions.
+
+ Low level disk I/O module is not included in this archive because the FatFs
+ module is only a generic file system layer and not depend on any specific
+ storage device. You have to provide a low level disk I/O module that written
+ to control your storage device.
+
+
+
+AGREEMENTS
+
+ FatFs module is an open source software to implement FAT file system to
+ small embedded systems. This is a free software and is opened for education,
+ research and commercial developments under license policy of following trems.
+
+ Copyright (C) 2010, ChaN, all right reserved.
+
+ * The FatFs module is a free software and there is NO WARRANTY.
+ * No restriction on use. You can use, modify and redistribute it for
+ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+ * Redistributions of source code must retain the above copyright notice.
+
+
+
+REVISION HISTORY
+
+ Feb 26, 2006 R0.00 Prototype
+
+ Apr 29, 2006 R0.01 First release.
+
+ Jun 01, 2006 R0.02 Added FAT12.
+ Removed unbuffered mode.
+ Fixed a problem on small (<32M) patition.
+
+ Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM.
+
+ Sep 22, 2006 R0.03 Added f_rename.
+ Changed option _FS_MINIMUM to _FS_MINIMIZE.
+
+ Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast.
+ Fixed f_mkdir creates incorrect directory on FAT32.
+
+ Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs)
+ Changed some APIs for multiple drive system.
+ Added f_mkfs. (FatFs)
+ Added _USE_FAT32 option. (Tiny-FatFs)
+
+ Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs)
+ Fixed an endian sensitive code in f_mkfs. (FatFs)
+ Added a capability of extending the file size to f_lseek.
+ Added minimization level 3.
+ Fixed a problem that can collapse a sector when recreate an
+ existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
+
+ May 05, 2007 R0.04b Added _USE_NTFLAG option.
+ Added FSInfo support.
+ Fixed some problems corresponds to FAT32. (Tiny-FatFs)
+ Fixed DBCS name can result FR_INVALID_NAME.
+ Fixed short seek (0 < ofs <= csize) collapses the file object.
+
+ Aug 25, 2007 R0.05 Changed arguments of f_read, f_write.
+ Changed arguments of f_mkfs. (FatFs)
+ Fixed f_mkfs on FAT32 creates incorrect FSInfo. (FatFs)
+ Fixed f_mkdir on FAT32 creates incorrect directory. (FatFs)
+
+ Feb 03, 2008 R0.05a Added f_truncate().
+ Added f_utime().
+ Fixed off by one error at FAT sub-type determination.
+ Fixed btr in f_read() can be mistruncated.
+ Fixed cached sector is not flushed when create and close without write.
+
+ Apr 01, 2008 R0.06 Added f_forward(). (Tiny-FatFs)
+ Added string functions: fputc(), fputs(), fprintf() and fgets().
+ Improved performance of f_lseek() on move to the same or following cluster.
+
+ Apr 01, 2010, R0.07 Merged Tiny-FatFs as a buffer configuration option.
+ Added long file name support.
+ Added multiple code page support.
+ Added re-entrancy for multitask operation.
+ Added auto cluster size selection to f_mkfs().
+ Added rewind option to f_readdir().
+ Changed result code of critical errors.
+ Renamed string functions to avoid name collision.
+
+ Apr 14, 2010, R0.07a Separated out OS dependent code on reentrant cfg.
+ Added multiple sector size support.
+
+ Jun 21, 2010, R0.07c Fixed f_unlink() may return FR_OK on error.
+ Fixed wrong cache control in f_lseek().
+ Added relative path feature.
+ Added f_chdir().
+ Added f_chdrive().
+ Added proper case conversion for extended characters.
+
+ Nov 03,'2010 R0.07e Separated out configuration options from ff.h to ffconf.h.
+ Added a configuration option, _LFN_UNICODE.
+ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+ Fixed name matching error on the 13 char boundary.
+ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
diff --git a/Projects/Webserver/Lib/FATFs/diskio.c b/Projects/Webserver/Lib/FATFs/diskio.c
new file mode 100644
index 000000000..c7c837ba4
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/diskio.c
@@ -0,0 +1,92 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+
+#include "diskio.h"
+
+/*-----------------------------------------------------------------------*/
+/* Inidialize a Drive */
+
+DSTATUS disk_initialize (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ return FR_OK;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Return Disk Status */
+
+DSTATUS disk_status (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ return FR_OK;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Sector(s) */
+
+DRESULT disk_read (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE *buff, /* Data buffer to store read data */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to read (1..255) */
+)
+{
+ DataflashManager_ReadBlocks_RAM(sector, count, buff);
+ return RES_OK;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Sector(s) */
+
+#if _READONLY == 0
+DRESULT disk_write (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ const BYTE *buff, /* Data to be written */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to write (1..255) */
+)
+{
+ DataflashManager_WriteBlocks_RAM(sector, count, buff);
+ return RES_OK;
+}
+#endif /* _READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Miscellaneous Functions */
+
+DRESULT disk_ioctl (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE ctrl, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ if (ctrl == CTRL_SYNC)
+ return RES_OK;
+ else
+ return RES_PARERR;
+}
+
+
+DWORD get_fattime (void)
+{
+ return ((DWORD)1 << 25) |
+ ((DWORD)1 << 21) |
+ ((DWORD)1 << 16) |
+ ((DWORD)1 << 11) |
+ ((DWORD)1 << 5) |
+ ((DWORD)1 << 0);
+}
diff --git a/Projects/Webserver/Lib/FATFs/diskio.h b/Projects/Webserver/Lib/FATFs/diskio.h
new file mode 100644
index 000000000..3df93ae7a
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/diskio.h
@@ -0,0 +1,72 @@
+/*-----------------------------------------------------------------------
+/ Low level disk interface modlue include file R0.07 (C)ChaN, 2010
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY 0 /* 1: Read-only mode */
+#define _USE_IOCTL 1
+
+#include "integer.h"
+#include "ff.h"
+
+#include "../DataflashManager.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+ RES_OK = 0, /* 0: Successful */
+ RES_ERROR, /* 1: R/W Error */
+ RES_WRPRT, /* 2: Write Protected */
+ RES_NOTRDY, /* 3: Not Ready */
+ RES_PARERR /* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+BOOL assign_drives (int argc, char *argv[]);
+DSTATUS disk_initialize (BYTE);
+DSTATUS disk_status (BYTE);
+DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+#if _READONLY == 0
+DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (BYTE, BYTE, void*);
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT 0x01 /* Drive not initialized */
+#define STA_NODISK 0x02 /* No medium in the drive */
+#define STA_PROTECT 0x04 /* Write protected */
+
+
+/* Command code for disk_ioctrl() */
+
+/* Generic command */
+#define CTRL_SYNC 0 /* Mandatory for write functions */
+#define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */
+#define GET_SECTOR_SIZE 2 /* Mandatory for multiple sector size cfg */
+#define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */
+#define CTRL_POWER 4
+#define CTRL_LOCK 5
+#define CTRL_EJECT 6
+/* MMC/SDC command */
+#define MMC_GET_TYPE 10
+#define MMC_GET_CSD 11
+#define MMC_GET_CID 12
+#define MMC_GET_OCR 13
+#define MMC_GET_SDSTAT 14
+/* ATA/CF command */
+#define ATA_GET_REV 20
+#define ATA_GET_MODEL 21
+#define ATA_GET_SN 22
+
+
+#define _DISKIO
+#endif
diff --git a/Projects/Webserver/Lib/FATFs/diskio.lst b/Projects/Webserver/Lib/FATFs/diskio.lst
new file mode 100644
index 000000000..d3e78054b
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/diskio.lst
@@ -0,0 +1,149 @@
+ 1 .file "diskio.c"
+ 2 __SREG__ = 0x3f
+ 3 __SP_H__ = 0x3e
+ 4 __SP_L__ = 0x3d
+ 5 __CCP__ = 0x34
+ 6 __tmp_reg__ = 0
+ 7 __zero_reg__ = 1
+ 15 .Ltext0:
+ 16 .section .text.disk_initialize,"ax",@progbits
+ 17 .global disk_initialize
+ 19 disk_initialize:
+ 20 .LFB54:
+ 21 .LSM0:
+ 22 .LVL0:
+ 23 /* prologue: function */
+ 24 /* frame size = 0 */
+ 25 .LSM1:
+ 26 0000 80E0 ldi r24,lo8(0)
+ 27 .LVL1:
+ 28 /* epilogue start */
+ 29 0002 0895 ret
+ 30 .LFE54:
+ 32 .section .text.disk_status,"ax",@progbits
+ 33 .global disk_status
+ 35 disk_status:
+ 36 .LFB55:
+ 37 .LSM2:
+ 38 .LVL2:
+ 39 /* prologue: function */
+ 40 /* frame size = 0 */
+ 41 .LSM3:
+ 42 0000 80E0 ldi r24,lo8(0)
+ 43 .LVL3:
+ 44 /* epilogue start */
+ 45 0002 0895 ret
+ 46 .LFE55:
+ 48 .section .text.disk_ioctl,"ax",@progbits
+ 49 .global disk_ioctl
+ 51 disk_ioctl:
+ 52 .LFB58:
+ 53 .LSM4:
+ 54 .LVL4:
+ 55 /* prologue: function */
+ 56 /* frame size = 0 */
+ 57 .LSM5:
+ 58 0000 6623 tst r22
+ 59 0002 01F0 breq .L6
+ 60 0004 84E0 ldi r24,lo8(4)
+ 61 .LVL5:
+ 62 0006 0895 ret
+ 63 .LVL6:
+ 64 .L6:
+ 65 0008 80E0 ldi r24,lo8(0)
+ 66 .LVL7:
+ 67 .LSM6:
+ 68 000a 0895 ret
+ 69 .LFE58:
+ 71 .section .text.get_fattime,"ax",@progbits
+ 72 .global get_fattime
+ 74 get_fattime:
+ 75 .LFB59:
+ 76 .LSM7:
+ 77 /* prologue: function */
+ 78 /* frame size = 0 */
+ 79 .LSM8:
+ 80 0000 61E2 ldi r22,lo8(35719201)
+ 81 0002 78E0 ldi r23,hi8(35719201)
+ 82 0004 81E2 ldi r24,hlo8(35719201)
+ 83 0006 92E0 ldi r25,hhi8(35719201)
+ 84 /* epilogue start */
+ 85 0008 0895 ret
+ 86 .LFE59:
+ 88 .section .text.disk_write,"ax",@progbits
+ 89 .global disk_write
+ 91 disk_write:
+ 92 .LFB57:
+ 93 .LSM9:
+ 94 .LVL8:
+ 95 0000 0F93 push r16
+ 96 .LVL9:
+ 97 /* prologue: function */
+ 98 /* frame size = 0 */
+ 99 0002 FB01 movw r30,r22
+ 100 .LSM10:
+ 101 0004 CA01 movw r24,r20
+ 102 0006 B901 movw r22,r18
+ 103 .LVL10:
+ 104 0008 402F mov r20,r16
+ 105 .LVL11:
+ 106 000a 50E0 ldi r21,lo8(0)
+ 107 000c 9F01 movw r18,r30
+ 108 .LVL12:
+ 109 000e 0E94 0000 call DataflashManager_WriteBlocks_RAM
+ 110 .LVL13:
+ 111 .LSM11:
+ 112 0012 80E0 ldi r24,lo8(0)
+ 113 /* epilogue start */
+ 114 0014 0F91 pop r16
+ 115 .LVL14:
+ 116 0016 0895 ret
+ 117 .LFE57:
+ 119 .section .text.disk_read,"ax",@progbits
+ 120 .global disk_read
+ 122 disk_read:
+ 123 .LFB56:
+ 124 .LSM12:
+ 125 .LVL15:
+ 126 0000 0F93 push r16
+ 127 .LVL16:
+ 128 /* prologue: function */
+ 129 /* frame size = 0 */
+ 130 0002 FB01 movw r30,r22
+ 131 .LSM13:
+ 132 0004 CA01 movw r24,r20
+ 133 0006 B901 movw r22,r18
+ 134 .LVL17:
+ 135 0008 402F mov r20,r16
+ 136 .LVL18:
+ 137 000a 50E0 ldi r21,lo8(0)
+ 138 000c 9F01 movw r18,r30
+ 139 .LVL19:
+ 140 000e 0E94 0000 call DataflashManager_ReadBlocks_RAM
+ 141 .LVL20:
+ 142 .LSM14:
+ 143 0012 80E0 ldi r24,lo8(0)
+ 144 /* epilogue start */
+ 145 0014 0F91 pop r16
+ 146 .LVL21:
+ 147 0016 0895 ret
+ 148 .LFE56:
+ 214 .Letext0:
+DEFINED SYMBOLS
+ *ABS*:00000000 diskio.c
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:2 *ABS*:0000003f __SREG__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:3 *ABS*:0000003e __SP_H__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:4 *ABS*:0000003d __SP_L__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:5 *ABS*:00000034 __CCP__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:6 *ABS*:00000000 __tmp_reg__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:7 *ABS*:00000001 __zero_reg__
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:19 .text.disk_initialize:00000000 disk_initialize
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:35 .text.disk_status:00000000 disk_status
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:51 .text.disk_ioctl:00000000 disk_ioctl
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:74 .text.get_fattime:00000000 get_fattime
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:91 .text.disk_write:00000000 disk_write
+C:\Users\Dean\AppData\Local\Temp/cc5TUdwu.s:122 .text.disk_read:00000000 disk_read
+
+UNDEFINED SYMBOLS
+DataflashManager_WriteBlocks_RAM
+DataflashManager_ReadBlocks_RAM
diff --git a/Projects/Webserver/Lib/FATFs/ff.c b/Projects/Webserver/Lib/FATFs/ff.c
new file mode 100644
index 000000000..6382fea1f
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/ff.c
@@ -0,0 +1,3153 @@
+/*----------------------------------------------------------------------------/
+/ FatFs - FAT file system module R0.07e (C)ChaN, 2010
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/ Copyright (C) 2010, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00 Prototype.
+/
+/ Apr 29,'06 R0.01 First stable version.
+/
+/ Jun 01,'06 R0.02 Added FAT12 support.
+/ Removed unbuffered mode.
+/ Fixed a problem on small (<32M) patition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03 Added f_rename().
+/ Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algolithm to write files fast.
+/ Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04 Supported multiple drive system.
+/ Changed some interfaces for multiple drive system.
+/ Changed f_mountdrv() to f_mount().
+/ Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a plysical drive.
+/ Added a capability of extending file size to f_lseek().
+/ Added minimization level 3.
+/ Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/ Added FSInfo support.
+/ Fixed DBCS name can result FR_INVALID_NAME.
+/ Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
+/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/ Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/ Fixed off by one error at FAT sub-type determination.
+/ Fixed btr in f_read() can be mistruncated.
+/ Fixed cached sector is not flushed when create and close
+/ without write.
+/
+/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
+/ Improved performance of f_lseek() on moving to the same
+/ or following cluster.
+/
+/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option.
+/ Added long file name support.
+/ Added multiple code page support.
+/ Added re-entrancy for multitask operation.
+/ Added auto cluster size selection to f_mkfs().
+/ Added rewind option to f_readdir().
+/ Changed result code of critical errors.
+/ Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/ Added multiple sector size support.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/ Fixed wrong cache control in f_lseek().
+/ Added relative path feature.
+/ Added f_chdir() and f_chdrive().
+/ Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/ Fixed name matching error on the 13 char boundary.
+/ Added a configuration option, _LFN_UNICODE.
+/ Changed f_readdir() to return the SFN with always upper
+/ case on non-LFN cfg.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h" /* FatFs configurations and declarations */
+#include "diskio.h" /* Declarations of low level disk I/O functions */
+
+/*--------------------------------------------------------------------------
+
+ Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 0x007E
+#error Wrong include file (ff.h).
+#endif
+
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
+
+#else
+#define ENTER_FF(fs)
+#define LEAVE_FF(fs, res) return res
+
+#endif
+
+#define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Name status flags */
+#define NS 11 /* Offset of name status byte */
+#define NS_LOSS 0x01 /* Out of 8.3 format */
+#define NS_LFN 0x02 /* Force to create LFN entry */
+#define NS_LAST 0x04 /* Last segment */
+#define NS_BODY 0x08 /* Lower case flag (body) */
+#define NS_EXT 0x10 /* Lower case flag (ext) */
+#define NS_DOT 0x20 /* Dot entry */
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Private Work Area
+
+---------------------------------------------------------------------------*/
+
+#if _DRIVES < 1 || _DRIVES > 9
+#error Number of drives must be 1-9.
+#endif
+static
+FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */
+
+static
+WORD Fsid; /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE Drive; /* Current drive */
+#endif
+
+
+#if _USE_LFN == 1 /* LFN with static LFN working buffer */
+static
+WCHAR LfnBuf[_MAX_LFN + 1];
+#define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR *lp = LfnBuf
+#define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
+
+#elif _USE_LFN > 1 /* LFN with dynamic LFN working buffer */
+#define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR lbuf[_MAX_LFN + 1], *lp = lbuf
+#define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
+
+#else /* No LFN */
+#define NAMEBUF(sp,lp) BYTE sp[12]
+#define INITBUF(dj,sp,lp) dj.fn = sp
+
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, int cnt) {
+ char *d = (char*)dst;
+ const char *s = (const char *)src;
+ while (cnt--) *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, int cnt) {
+ char *d = (char*)dst;
+ while (cnt--) *d++ = (char)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, int cnt) {
+ const char *d = (const char *)dst, *s = (const char *)src;
+ int r = 0;
+ while (cnt-- && (r = *d++ - *s++) == 0) ;
+ return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+ while (*str && *str != chr) str++;
+ return *str;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+BOOL lock_fs (
+ FATFS *fs /* File system object */
+)
+{
+ return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+ FATFS *fs, /* File system object */
+ FRESULT res /* Result code to be returned */
+)
+{
+ if (res != FR_NOT_ENABLED &&
+ res != FR_INVALID_DRIVE &&
+ res != FR_INVALID_OBJECT &&
+ res != FR_TIMEOUT) {
+ ff_rel_grant(fs->sobj);
+ }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+ FATFS *fs, /* File system object */
+ DWORD sector /* Sector number to make apperance in the fs->win[] */
+) /* Move to zero only writes back dirty window */
+{
+ DWORD wsect;
+
+
+ wsect = fs->winsect;
+ if (wsect != sector) { /* Changed current window */
+#if !_FS_READONLY
+ if (fs->wflag) { /* Write back dirty window if needed */
+ if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->wflag = 0;
+ if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */
+ BYTE nf;
+ for (nf = fs->n_fats; nf > 1; nf--) { /* Refrect the change to all FAT copies */
+ wsect += fs->sects_fat;
+ disk_write(fs->drive, fs->win, wsect, 1);
+ }
+ }
+ }
+#endif
+ if (sector) {
+ if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->winsect = sector;
+ }
+ }
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
+ FATFS *fs /* File system object */
+)
+{
+ FRESULT res;
+
+
+ res = move_window(fs, 0);
+ if (res == FR_OK) {
+ /* Update FSInfo sector if needed */
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+ fs->winsect = 0;
+ mem_set(fs->win, 0, 512);
+ ST_WORD(fs->win+BS_55AA, 0xAA55);
+ ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+ ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+ ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+ ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+ disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
+ fs->fsi_flag = 0;
+ }
+ /* Make sure that no pending write process in the physical drive */
+ if (disk_ioctl(fs->drive, CTRL_SYNC, (void*)NULL) != RES_OK)
+ res = FR_DISK_ERR;
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to get the link information */
+)
+{
+ UINT wc, bc;
+ DWORD fsect;
+
+
+ if (clst < 2 || clst >= fs->max_clust) /* Range check */
+ return 1;
+
+ fsect = fs->fatbase;
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = clst; bc += bc / 2;
+ if (move_window(fs, fsect + (bc / SS(fs)))) break;
+ wc = fs->win[bc & (SS(fs) - 1)]; bc++;
+ if (move_window(fs, fsect + (bc / SS(fs)))) break;
+ wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
+ return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+ case FS_FAT16 :
+ if (move_window(fs, fsect + (clst / (SS(fs) / 2)))) break;
+ return LD_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)]);
+
+ case FS_FAT32 :
+ if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break;
+ return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
+ }
+
+ return 0xFFFFFFFF; /* An error occured at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+ FATFS *fs, /* File system object */
+ DWORD clst, /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */
+ DWORD val /* New value to mark the cluster */
+)
+{
+ UINT bc;
+ BYTE *p;
+ DWORD fsect;
+ FRESULT res;
+
+
+ if (clst < 2 || clst >= fs->max_clust) { /* Range check */
+ res = FR_INT_ERR;
+
+ } else {
+ fsect = fs->fatbase;
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = clst; bc += bc / 2;
+ res = move_window(fs, fsect + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc & (SS(fs) - 1)];
+ *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+ bc++;
+ fs->wflag = 1;
+ res = move_window(fs, fsect + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc & (SS(fs) - 1)];
+ *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+ break;
+
+ case FS_FAT16 :
+ res = move_window(fs, fsect + (clst / (SS(fs) / 2)));
+ if (res != FR_OK) break;
+ ST_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)], (WORD)val);
+ break;
+
+ case FS_FAT32 :
+ res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
+ if (res != FR_OK) break;
+ ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
+ break;
+
+ default :
+ res = FR_INT_ERR;
+ }
+ fs->wflag = 1;
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to remove a chain from */
+)
+{
+ FRESULT res;
+ DWORD nxt;
+
+
+ if (clst < 2 || clst >= fs->max_clust) { /* Check the range of cluster# */
+ res = FR_INT_ERR;
+
+ } else {
+ res = FR_OK;
+ while (clst < fs->max_clust) { /* Not a last link? */
+ nxt = get_fat(fs, clst); /* Get cluster status */
+ if (nxt == 0) break; /* Empty cluster? */
+ if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
+ if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
+ res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
+ if (res != FR_OK) break;
+ if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
+ fs->free_clust++;
+ fs->fsi_flag = 1;
+ }
+ clst = nxt; /* Next cluster */
+ }
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+ DWORD cs, ncl, scl, mcl;
+
+
+ mcl = fs->max_clust;
+ if (clst == 0) { /* Create new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (scl == 0 || scl >= mcl) scl = 1;
+ }
+ else { /* Stretch existing chain */
+ cs = get_fat(fs, clst); /* Check the cluster status */
+ if (cs < 2) return 1; /* It is an invalid cluster */
+ if (cs < mcl) return cs; /* It is already followed by next cluster */
+ scl = clst;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= mcl) { /* Wrap around */
+ ncl = 2;
+ if (ncl > scl) return 0; /* No free custer */
+ }
+ cs = get_fat(fs, ncl); /* Get the cluster status */
+ if (cs == 0) break; /* Found a free cluster */
+ if (cs == 0xFFFFFFFF || cs == 1)/* An error occured */
+ return cs;
+ if (ncl == scl) return 0; /* No free custer */
+ }
+
+ if (put_fat(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "in use" */
+ return 0xFFFFFFFF;
+ if (clst != 0) { /* Link it to the previous one if needed */
+ if (put_fat(fs, clst, ncl))
+ return 0xFFFFFFFF;
+ }
+
+ fs->last_clust = ncl; /* Update FSINFO */
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+ fs->fsi_flag = 1;
+ }
+
+ return ncl; /* Return new cluster number */
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to be converted */
+)
+{
+ clst -= 2;
+ if (clst >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
+ return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Seek directory index */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_seek (
+ DIR *dj, /* Pointer to directory object */
+ WORD idx /* Directory index number */
+)
+{
+ DWORD clst;
+ WORD ic;
+
+
+ dj->index = idx;
+ clst = dj->sclust;
+ if (clst == 1 || clst >= dj->fs->max_clust) /* Check start cluster range */
+ return FR_INT_ERR;
+ if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
+ clst = dj->fs->dirbase;
+
+ if (clst == 0) { /* Static table */
+ dj->clust = clst;
+ if (idx >= dj->fs->n_rootdir) /* Index is out of range */
+ return FR_INT_ERR;
+ dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */
+ }
+ else { /* Dynamic table */
+ ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */
+ while (idx >= ic) { /* Follow cluster chain */
+ clst = get_fat(dj->fs, clst); /* Get next cluster */
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
+ if (clst < 2 || clst >= dj->fs->max_clust) /* Reached to end of table or int error */
+ return FR_INT_ERR;
+ idx -= ic;
+ }
+ dj->clust = clst;
+ dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */
+ }
+
+ dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
+
+ return FR_OK; /* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory index next */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
+ DIR *dj, /* Pointer to directory object */
+ BOOL streach /* FALSE: Do not streach table, TRUE: Streach table if needed */
+)
+{
+ DWORD clst;
+ WORD i;
+
+
+ i = dj->index + 1;
+ if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
+ return FR_NO_FILE;
+
+ if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
+ dj->sect++; /* Next sector */
+
+ if (dj->clust == 0) { /* Static table */
+ if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
+ return FR_NO_FILE;
+ }
+ else { /* Dynamic table */
+ if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
+ clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
+ if (clst <= 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ if (clst >= dj->fs->max_clust) { /* When it reached end of dynamic table */
+#if !_FS_READONLY
+ BYTE c;
+ if (!streach) return FR_NO_FILE; /* When do not streach, report EOT */
+ clst = create_chain(dj->fs, dj->clust); /* Streach cluster chain */
+ if (clst == 0) return FR_DENIED; /* No free cluster */
+ if (clst == 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ /* Clean-up streached table */
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
+ mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
+ dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
+ for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
+ dj->fs->wflag = 1;
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+ dj->fs->winsect++;
+ }
+ dj->fs->winsect -= c; /* Rewind window address */
+#else
+ return FR_NO_FILE; /* Report EOT */
+#endif
+ }
+ dj->clust = clst; /* Initialize data for new cluster */
+ dj->sect = clust2sect(dj->fs, clst);
+ }
+ }
+ }
+
+ dj->index = i;
+ dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
+
+
+static
+BOOL cmp_lfn ( /* TRUE:Matched, FALSE:Not matched */
+ WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
+ BYTE *dir /* Pointer to the directory entry containing a part of LFN */
+)
+{
+ int i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ wc = ff_wtoupper(uc); /* Convert it to upper case */
+ if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
+ return FALSE; /* Not matched */
+ } else {
+ if (uc != 0xFFFF) return FALSE; /* Check filler */
+ }
+ } while (++s < 13); /* Repeat until all chars in the entry are checked */
+
+ if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */
+ return FALSE;
+
+ return TRUE; /* The part of LFN matched */
+}
+
+
+
+static
+BOOL pick_lfn ( /* TRUE:Succeeded, FALSE:Buffer overflow */
+ WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
+ BYTE *dir /* Pointer to the directory entry */
+)
+{
+ int i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
+
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
+ lfnbuf[i++] = wc = uc; /* Store it */
+ } else {
+ if (uc != 0xFFFF) return FALSE; /* Check filler */
+ }
+ } while (++s < 13); /* Read all character in the entry */
+
+ if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */
+ if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
+ lfnbuf[i] = 0;
+ }
+
+ return TRUE;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+ const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
+ BYTE *dir, /* Pointer to the directory entry */
+ BYTE ord, /* LFN order (1-20) */
+ BYTE sum /* SFN sum */
+)
+{
+ int i, s;
+ WCHAR wc;
+
+
+ dir[LDIR_Chksum] = sum; /* Set check sum */
+ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
+ dir[LDIR_Type] = 0;
+ ST_WORD(dir+LDIR_FstClusLO, 0);
+
+ i = (ord - 1) * 13; /* Get offset in the LFN buffer */
+ s = wc = 0;
+ do {
+ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
+ ST_WORD(dir+LfnOfs[s], wc); /* Put it */
+ if (!wc) wc = 0xFFFF; /* Padding chars following last char */
+ } while (++s < 13);
+ if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */
+ dir[LDIR_Ord] = ord; /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+ BYTE *dst, /* Pointer to genartated SFN */
+ const BYTE *src, /* Pointer to source SFN to be modified */
+ const WCHAR *lfn, /* Pointer to LFN */
+ WORD num /* Sequense number */
+)
+{
+ char ns[8];
+ int i, j;
+
+
+ mem_cpy(dst, src, 11);
+
+ if (num > 5) { /* On many collisions, generate a hash number instead of sequencial number */
+ do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
+ }
+
+ /* itoa */
+ i = 7;
+ do {
+ ns[i--] = (num % 10) + '0';
+ num /= 10;
+ } while (num);
+ ns[i] = '~';
+
+ /* Append the number */
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+ if (IsDBCS1(dst[j])) {
+ if (j == i - 1) break;
+ j++;
+ }
+ }
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+ const BYTE *dir /* Ptr to directory entry */
+)
+{
+ BYTE sum = 0;
+ int n = 11;
+
+ do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+ return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+ DIR *dj /* Pointer to the directory object linked to the file name */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord, sum;
+#endif
+
+ res = dir_seek(dj, 0); /* Rewind directory object */
+ if (res != FR_OK) return res;
+
+#if _USE_LFN
+ ord = sum = 0xFF;
+#endif
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (dj->lfn) {
+ if (c & 0x40) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= 0xBF; ord = c; /* LFN start order */
+ dj->lfn_idx = dj->index;
+ }
+ /* Check validity of the LFN entry and compare it with given name */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ }
+ } else { /* An SFN entry is found */
+ if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
+ ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+ if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
+ }
+ }
+#else /* Non LFN configuration */
+ if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, FALSE); /* Next entry */
+ } while (res == FR_OK);
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+ DIR *dj /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+ res = FR_NO_FILE;
+ while (dj->sect) {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (c & 0x40) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= 0xBF; ord = c;
+ dj->lfn_idx = dj->index;
+ }
+ /* Check LFN validity and capture it */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ } else { /* An SFN entry is found */
+ if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+ dj->lfn_idx = 0xFFFF; /* It has no LFN. */
+ break;
+ }
+ }
+#else /* Non LFN configuration */
+ if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, FALSE); /* Next entry */
+ if (res != FR_OK) break;
+ }
+
+ if (res != FR_OK) dj->sect = 0;
+
+ return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+ DIR *dj /* Target directory with object name to be created */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN /* LFN configuration */
+ WORD n, ne, is;
+ BYTE sn[12], *fn, sum;
+ WCHAR *lfn;
+
+
+ fn = dj->fn; lfn = dj->lfn;
+ mem_cpy(sn, fn, 12);
+
+ if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME; /* Cannot create dot entry */
+
+ if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
+ fn[NS] = 0; dj->lfn = NULL; /* Find only SFN */
+ for (n = 1; n < 100; n++) {
+ gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ res = dir_find(dj); /* Check if the name collides with existing SFN */
+ if (res != FR_OK) break;
+ }
+ if (n == 100) return FR_DENIED; /* Abort if too many collisions */
+ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
+ fn[NS] = sn[NS]; dj->lfn = lfn;
+ }
+
+ if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
+ for (ne = 0; lfn[ne]; ne++) ;
+ ne = (ne + 25) / 13;
+ } else { /* Otherwise reserve only an SFN entry. */
+ ne = 1;
+ }
+
+ /* Reserve contiguous entries */
+ res = dir_seek(dj, 0);
+ if (res != FR_OK) return res;
+ n = is = 0;
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir; /* Check the entry status */
+ if (c == 0xE5 || c == 0) { /* Is it a blank entry? */
+ if (n == 0) is = dj->index; /* First index of the contigulus entry */
+ if (++n == ne) break; /* A contiguous entry that requiered count is found */
+ } else {
+ n = 0; /* Not a blank entry. Restart to search */
+ }
+ res = dir_next(dj, TRUE); /* Next entry with table streach */
+ } while (res == FR_OK);
+
+ if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
+ res = dir_seek(dj, is);
+ if (res == FR_OK) {
+ sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
+ ne--;
+ do { /* Store LFN entries in bottom first */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+ dj->fs->wflag = 1;
+ res = dir_next(dj, FALSE); /* Next entry */
+ } while (res == FR_OK && --ne);
+ }
+ }
+
+#else /* Non LFN configuration */
+ res = dir_seek(dj, 0);
+ if (res == FR_OK) {
+ do { /* Find a blank entry for the SFN */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir;
+ if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */
+ res = dir_next(dj, TRUE); /* Next entry with table streach */
+ } while (res == FR_OK);
+ }
+#endif
+
+ if (res == FR_OK) { /* Initialize the SFN entry */
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ dir = dj->dir;
+ mem_set(dir, 0, 32); /* Clean the entry */
+ mem_cpy(dir, dj->fn, 11); /* Put SFN */
+ dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
+ dj->fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+ DIR *dj /* Directory object pointing the entry to be removed */
+)
+{
+ FRESULT res;
+#if _USE_LFN /* LFN configuration */
+ WORD i;
+
+ i = dj->index; /* SFN index */
+ res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
+ if (res == FR_OK) {
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ *dj->dir = 0xE5; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
+ res = dir_next(dj, FALSE); /* Next entry */
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;
+ }
+
+#else /* Non LFN configuration */
+ res = dir_seek(dj, dj->index);
+ if (res == FR_OK) {
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ *dj->dir = 0xE5; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ }
+ }
+#endif
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+ DIR *dj, /* Pointer to the directory object */
+ const XCHAR **path /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+ static const BYTE cvt[] = _EXCVT;
+#endif
+
+#if _USE_LFN /* LFN configuration */
+ BYTE b, cf;
+ WCHAR w, *lfn;
+ int i, ni, si, di;
+ const XCHAR *p;
+
+ /* Create LFN in Unicode */
+ si = di = 0;
+ p = *path;
+ lfn = dj->lfn;
+ for (;;) {
+ w = p[si++]; /* Get a character */
+ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
+ if (di >= _MAX_LFN) /* Reject too long name */
+ return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+ w &= 0xFF;
+ if (IsDBCS1(w)) { /* If it is a DBC 1st byte */
+ b = p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(b)) /* Reject invalid code for DBC */
+ return FR_INVALID_NAME;
+ w = (w << 8) + b;
+ }
+ w = ff_convert(w, 1); /* Convert OEM to Unicode */
+ if (!w) return FR_INVALID_NAME; /* Reject invalid code */
+#endif
+ if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+ return FR_INVALID_NAME;
+ lfn[di++] = w; /* Store the Unicode char */
+ }
+ *path = &p[si]; /* Rerurn pointer to the next segment */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+#if _FS_RPATH
+ if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
+ (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
+ lfn[di] = 0;
+ for (i = 0; i < 11; i++)
+ dj->fn[i] = (i < di) ? '.' : ' ';
+ dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
+ return FR_OK;
+ }
+#endif
+ while (di) { /* Strip trailing spaces and dots */
+ w = lfn[di - 1];
+ if (w != ' ' && w != '.') break;
+ di--;
+ }
+ if (!di) return FR_INVALID_NAME; /* Reject null string */
+
+ lfn[di] = 0; /* LFN is created */
+
+ /* Create SFN in directory form */
+ mem_set(dj->fn, ' ', 11);
+ for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
+ if (si) cf |= NS_LOSS | NS_LFN;
+ while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
+
+ b = i = 0; ni = 8;
+ for (;;) {
+ w = lfn[si++]; /* Get an LFN char */
+ if (!w) break; /* Break on enf of the LFN */
+ if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
+ cf |= NS_LOSS | NS_LFN; continue;
+ }
+
+ if (i >= ni || si == di) { /* Extension or end of SFN */
+ if (ni == 11) { /* Long extension */
+ cf |= NS_LOSS | NS_LFN; break;
+ }
+ if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
+ if (si > di) break; /* No extension */
+ si = di; i = 8; ni = 11; /* Enter extension section */
+ b <<= 2; continue;
+ }
+
+ if (w >= 0x80) { /* Non ASCII char */
+#ifdef _EXCVT
+ w = ff_convert(w, 0); /* Unicode -> OEM code */
+ if (w) w = cvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
+#else
+ w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
+#endif
+ cf |= NS_LFN; /* Force create LFN entry */
+ }
+
+ if (_DF1S && w >= 0x100) { /* Double byte char */
+ if (i >= ni - 1) {
+ cf |= NS_LOSS | NS_LFN; i = ni; continue;
+ }
+ dj->fn[i++] = (BYTE)(w >> 8);
+ } else { /* Single byte char */
+ if (!w || chk_chr("+,;[=]", w)) { /* Replace illegal chars for SFN */
+ w = '_'; cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
+ } else {
+ if (IsUpper(w)) { /* ASCII large capital */
+ b |= 2;
+ } else {
+ if (IsLower(w)) { /* ASCII small capital */
+ b |= 1; w -= 0x20;
+ }
+ }
+ }
+ }
+ dj->fn[i++] = (BYTE)w;
+ }
+
+ if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
+ cf |= NS_LFN;
+ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
+ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
+ }
+
+ dj->fn[NS] = cf; /* SFN is created */
+
+ return FR_OK;
+
+
+#else /* Non-LFN configuration */
+ BYTE b, c, d, *sfn;
+ int ni, si, i;
+ const char *p;
+
+ /* Create file name in directory form */
+ sfn = dj->fn;
+ mem_set(sfn, ' ', 11);
+ si = i = b = 0; ni = 8;
+ p = *path;
+#if _FS_RPATH
+ if (p[si] == '.') { /* Is this a dot entry? */
+ for (;;) {
+ c = p[si++];
+ if (c != '.' || si >= 3) break;
+ sfn[i++] = c;
+ }
+ if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+ *path = &p[si]; /* Rerurn pointer to the next segment */
+ sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
+ return FR_OK;
+ }
+#endif
+ for (;;) {
+ c = p[si++];
+ if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
+ if (c == '.' || i >= ni) {
+ if (ni != 8 || c != '.') return FR_INVALID_NAME;
+ i = 8; ni = 11;
+ b <<= 2; continue;
+ }
+ if (c >= 0x80) { /* Extended char */
+#ifdef _EXCVT
+ c = cvt[c - 0x80]; /* Convert extend char (SBCS) */
+#else
+ b |= 3; /* Eliminate NT flag if ext char is exist */
+#if !_DF1S /* ASCII only cfg */
+ return FR_INVALID_NAME;
+#endif
+#endif
+ }
+ if (IsDBCS1(c)) { /* DBC 1st byte? */
+ d = p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+ return FR_INVALID_NAME;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ } else { /* Single byte code */
+ if (chk_chr(" \"*+,[=]|\x7F", c)) /* Reject illegal chrs for SFN */
+ return FR_INVALID_NAME;
+ if (IsUpper(c)) { /* ASCII large capital? */
+ b |= 2;
+ } else {
+ if (IsLower(c)) { /* ASCII small capital? */
+ b |= 1; c -= 0x20;
+ }
+ }
+ sfn[i++] = c;
+ }
+ }
+ *path = &p[si]; /* Rerurn pointer to the next segment */
+ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+
+ if (!i) return FR_INVALID_NAME; /* Reject null string */
+ if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Filename has only small capital) */
+
+ sfn[NS] = c; /* Store NT flag, File name is created */
+
+ return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo ( /* No return code */
+ DIR *dj, /* Pointer to the directory object */
+ FILINFO *fno /* Pointer to the file information to be filled */
+)
+{
+ int i;
+ BYTE c, nt, *dir;
+ char *p;
+
+
+ p = fno->fname;
+ if (dj->sect) {
+ dir = dj->dir;
+ nt = dir[DIR_NTres]; /* NT flag */
+ for (i = 0; i < 8; i++) { /* Copy name body */
+ c = dir[i];
+ if (c == ' ') break;
+ if (c == 0x05) c = 0xE5;
+ if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+ *p++ = c;
+ }
+ if (dir[8] != ' ') { /* Copy name extension */
+ *p++ = '.';
+ for (i = 8; i < 11; i++) {
+ c = dir[i];
+ if (c == ' ') break;
+ if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+ *p++ = c;
+ }
+ }
+ fno->fattrib = dir[DIR_Attr]; /* Attribute */
+ fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
+ fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
+ fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
+ }
+ *p = 0;
+
+#if _USE_LFN
+ if (fno->lfname) {
+ XCHAR *tp = fno->lfname;
+ WCHAR w, *lfn;
+
+ i = 0;
+ if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+ lfn = dj->lfn;
+ while ((w = *lfn++) != 0) { /* Get an LFN char */
+#if !_LFN_UNICODE
+ w = ff_convert(w, 0); /* Unicode -> OEM conversion */
+ if (!w) { i = 0; break; } /* Could not convert, no LFN */
+ if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC */
+ tp[i++] = (XCHAR)(w >> 8);
+#endif
+ if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overrun, no LFN */
+ tp[i++] = (XCHAR)w;
+ }
+ }
+ tp[i] = 0; /* Terminator */
+ }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
+ DIR *dj, /* Directory object to return last directory and found object */
+ const XCHAR *path /* Full-path string to find a file or directory */
+)
+{
+ FRESULT res;
+ BYTE *dir, last;
+
+
+ while (!_USE_LFN && *path == ' ') path++; /* Skip leading spaces */
+#if _FS_RPATH
+ if (*path == '/' || *path == '\\') { /* There is a heading separator */
+ path++; dj->sclust = 0; /* Strip it and start from the root dir */
+ } else { /* No heading saparator */
+ dj->sclust = dj->fs->cdir; /* Start from the current dir */
+ }
+#else
+ if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
+ path++;
+ dj->sclust = 0; /* Start from the root dir */
+#endif
+
+ if ((UINT)*path < ' ') { /* Null path means the start directory itself */
+ res = dir_seek(dj, 0);
+ dj->dir = NULL;
+
+ } else { /* Follow path */
+ for (;;) {
+ res = create_name(dj, &path); /* Get a segment */
+ if (res != FR_OK) break;
+ res = dir_find(dj); /* Find it */
+ last = *(dj->fn+NS) & NS_LAST;
+ if (res != FR_OK) { /* Could not find the object */
+ if (res == FR_NO_FILE && !last)
+ res = FR_NO_PATH;
+ break;
+ }
+ if (last) break; /* Last segment match. Function completed. */
+ dir = dj->dir; /* There is next segment. Follow the sub directory */
+ if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+ res = FR_NO_PATH; break;
+ }
+ dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+ }
+ }
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is an FAT boot record */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
+ FATFS *fs, /* File system object */
+ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+ if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK) /* Load boot record */
+ return 3;
+ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+ return 2;
+
+ if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+ return 0;
+ if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+ return 0;
+
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Make sure that the file system is valid */
+/*-----------------------------------------------------------------------*/
+
+
+FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occured */
+ const XCHAR **path, /* Pointer to pointer to the path name (drive number) */
+ FATFS **rfs, /* Pointer to pointer to the found file system object */
+ BYTE chk_wp /* !=0: Check media write protection for write access */
+)
+{
+ BYTE fmt, *tbl;
+ UINT vol;
+ DSTATUS stat;
+ DWORD bsect, fsize, tsect, mclst;
+ const XCHAR *p = *path;
+ FATFS *fs;
+
+ /* Get logical drive number from the path name */
+ vol = p[0] - '0'; /* Is there a drive number? */
+ if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
+ p += 2; *path = p; /* Return pointer to the path name */
+ } else { /* No drive number is given */
+#if _FS_RPATH
+ vol = Drive; /* Use current drive */
+#else
+ vol = 0; /* Use drive 0 */
+#endif
+ }
+
+ /* Check if the logical drive is valid or not */
+ if (vol >= _DRIVES) /* Is the drive number valid? */
+ return FR_INVALID_DRIVE;
+ *rfs = fs = FatFs[vol]; /* Returen pointer to the corresponding file system object */
+ if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
+
+ ENTER_FF(fs); /* Lock file system */
+
+ if (fs->fs_type) { /* If the logical drive has been mounted */
+ stat = disk_status(fs->drive);
+ if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ return FR_OK; /* The file system object is valid */
+ }
+ }
+
+ /* The logical drive must be mounted. Following code attempts to mount the volume */
+
+ fs->fs_type = 0; /* Clear the file system object */
+ fs->drive = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
+ stat = disk_initialize(fs->drive); /* Initialize low level disk I/O layer */
+ if (stat & STA_NOINIT) /* Check if the drive is ready */
+ return FR_NOT_READY;
+#if _MAX_SS != 512 /* Get disk sector size if needed */
+ if (disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
+ return FR_NO_FILESYSTEM;
+#endif
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ /* Search FAT partition on the drive */
+ fmt = check_fs(fs, bsect = 0); /* Check sector 0 as an SFD format */
+ if (fmt == 1) { /* Not an FAT boot record, it may be patitioned */
+ /* Check a partition listed in top of the partition table */
+ tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
+ if (tbl[4]) { /* Is the partition existing? */
+ bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
+ fmt = check_fs(fs, bsect); /* Check the partition */
+ }
+ }
+ if (fmt == 3) return FR_DISK_ERR;
+ if (fmt || LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* No valid FAT patition is found */
+ return FR_NO_FILESYSTEM;
+
+ /* Initialize the file system object */
+ fsize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
+ if (!fsize) fsize = LD_DWORD(fs->win+BPB_FATSz32);
+ fs->sects_fat = fsize;
+ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
+ fsize *= fs->n_fats; /* (Number of sectors in FAT area) */
+ fs->fatbase = bsect + LD_WORD(fs->win+BPB_RsvdSecCnt); /* FAT start sector (lba) */
+ fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
+ fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Nmuber of root directory entries */
+ tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
+ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+ fs->max_clust = mclst = (tsect /* Last cluster# + 1 (Number of clusters + 2) */
+ - LD_WORD(fs->win+BPB_RsvdSecCnt) - fsize - fs->n_rootdir / (SS(fs)/32)
+ ) / fs->csize + 2;
+
+ fmt = FS_FAT12; /* Determine the FAT sub type */
+ if (mclst >= 0xFF7) fmt = FS_FAT16; /* Number of clusters >= 0xFF5 */
+ if (mclst >= 0xFFF7) fmt = FS_FAT32; /* Number of clusters >= 0xFFF5 */
+
+ if (fmt == FS_FAT32)
+ fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
+ else
+ fs->dirbase = fs->fatbase + fsize; /* Root directory start sector (lba) */
+ fs->database = fs->fatbase + fsize + fs->n_rootdir / (SS(fs)/32); /* Data start sector (lba) */
+
+#if !_FS_READONLY
+ /* Initialize allocation information */
+ fs->free_clust = 0xFFFFFFFF;
+ fs->wflag = 0;
+ /* Get fsinfo if needed */
+ if (fmt == FS_FAT32) {
+ fs->fsi_flag = 0;
+ fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+ if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
+ LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+ LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+ LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+ fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+ fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+ }
+ }
+#endif
+ fs->fs_type = fmt; /* FAT sub-type */
+ fs->winsect = 0; /* Invalidate sector cache */
+#if _FS_RPATH
+ fs->cdir = 0; /* Current directory (root dir) */
+#endif
+ fs->id = ++Fsid; /* File system mount ID */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
+ FATFS *fs, /* Pointer to the file system object */
+ WORD id /* Member id of the target object to be checked */
+)
+{
+ if (!fs || !fs->fs_type || fs->id != id)
+ return FR_INVALID_OBJECT;
+
+ ENTER_FF(fs); /* Lock file system */
+
+ if (disk_status(fs->drive) & STA_NOINIT)
+ return FR_NOT_READY;
+
+ return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+ BYTE vol, /* Logical drive number to be mounted/unmounted */
+ FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+ FATFS *rfs;
+
+
+ if (vol >= _DRIVES) /* Check if the drive number is valid */
+ return FR_INVALID_DRIVE;
+ rfs = FatFs[vol]; /* Get current fs object */
+
+ if (rfs) {
+#if _FS_REENTRANT /* Discard sync object of the current volume */
+ if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+ rfs->fs_type = 0; /* Clear old fs object */
+ }
+
+ if (fs) {
+ fs->fs_type = 0; /* Clear new fs object */
+#if _FS_REENTRANT /* Create sync object for the new volume */
+ if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+ }
+ FatFs[vol] = fs; /* Register new fs object */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+ FIL *fp, /* Pointer to the blank file object */
+ const XCHAR *path, /* Pointer to the file name */
+ BYTE mode /* Access mode and file open mode flags */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+
+
+ fp->fs = NULL; /* Clear file object */
+#if !_FS_READONLY
+ mode &= (FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW);
+ res = chk_mounted(&path, &dj.fs, (BYTE)(mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)));
+#else
+ mode &= FA_READ;
+ res = chk_mounted(&path, &dj.fs, 0);
+#endif
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+
+#if !_FS_READONLY
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+ DWORD ps, cl;
+
+ if (res != FR_OK) { /* No file, create new */
+ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
+ res = dir_register(&dj);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+ mode |= FA_CREATE_ALWAYS;
+ dir = dj.dir; /* Created entry (SFN entry) */
+ }
+ else { /* Any object is already existing */
+ if (mode & FA_CREATE_NEW) /* Cannot create new */
+ LEAVE_FF(dj.fs, FR_EXIST);
+ dir = dj.dir;
+ if (!dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR))) /* Cannot overwrite it (R/O or DIR) */
+ LEAVE_FF(dj.fs, FR_DENIED);
+ if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero on over write mode */
+ cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); /* Get start cluster */
+ ST_WORD(dir+DIR_FstClusHI, 0); /* cluster = 0 */
+ ST_WORD(dir+DIR_FstClusLO, 0);
+ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
+ dj.fs->wflag = 1;
+ ps = dj.fs->winsect; /* Remove the cluster chain */
+ if (cl) {
+ res = remove_chain(dj.fs, cl);
+ if (res) LEAVE_FF(dj.fs, res);
+ dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+ }
+ res = move_window(dj.fs, ps);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+ }
+ }
+ if (mode & FA_CREATE_ALWAYS) {
+ dir[DIR_Attr] = 0; /* Reset attribute */
+ ps = get_fattime();
+ ST_DWORD(dir+DIR_CrtTime, ps); /* Created time */
+ dj.fs->wflag = 1;
+ mode |= FA__WRITTEN; /* Set file changed flag */
+ }
+ }
+ /* Open an existing file */
+ else {
+#endif /* !_FS_READONLY */
+ if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
+ dir = dj.dir;
+ if (!dir || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */
+ LEAVE_FF(dj.fs, FR_NO_FILE);
+#if !_FS_READONLY
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ LEAVE_FF(dj.fs, FR_DENIED);
+ }
+ fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dj.dir;
+#endif
+ fp->flag = mode; /* File access mode */
+ fp->org_clust = /* File start cluster */
+ ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
+ fp->fptr = 0; fp->csect = 255; /* File pointer */
+ fp->dsect = 0;
+ fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */
+
+ LEAVE_FF(dj.fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+ FIL *fp, /* Pointer to the file object */
+ void *buff, /* Pointer to data buffer */
+ UINT btr, /* Number of bytes to read */
+ UINT *br /* Pointer to number of bytes read */
+)
+{
+ FRESULT res;
+ DWORD clst, sect, remain;
+ UINT rcnt, cc;
+ BYTE *rbuff = buff;
+
+
+ *br = 0; /* Initialize bytes read */
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr; /* Repeat until all data transferred */
+ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
+ clst = (fp->fptr == 0) ? /* On the top of the file? */
+ fp->org_clust : get_fat(fp->fs, fp->curr_clust);
+ if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->curr_clust = clst; /* Update current cluster */
+ fp->csect = 0; /* Reset sector offset in the cluster */
+ }
+ sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += fp->csect;
+ cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - fp->csect;
+ if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2
+#if _FS_TINY
+ if (fp->fs->wflag && fp->fs->winsect - sect < cc) /* Replace one of the read sectors with cached data if it contains a dirty sector */
+ mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) /* Replace one of the read sectors with cached data if it contains a dirty sector */
+ mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+ fp->csect += (BYTE)cc; /* Next sector address in the cluster */
+ rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */
+ if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (fp->dsect != sect) { /* Fill sector buffer with file data */
+ if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ fp->csect++; /* Next sector address in the cluster */
+ }
+ rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
+ if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#else
+ mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#endif
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+ FIL *fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ UINT btw, /* Number of bytes to write */
+ UINT *bw /* Pointer to number of bytes written */
+)
+{
+ FRESULT res;
+ DWORD clst, sect;
+ UINT wcnt, cc;
+ const BYTE *wbuff = buff;
+
+
+ *bw = 0; /* Initialize bytes written */
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */
+
+ for ( ; btw; /* Repeat until all data transferred */
+ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->org_clust; /* Follow from the origin */
+ if (clst == 0) /* When there is no cluster chain, */
+ fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
+ } else { /* Middle or end of the file */
+ clst = create_chain(fp->fs, fp->curr_clust); /* Follow or streach cluster chain */
+ }
+ if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->curr_clust = clst; /* Update current cluster */
+ fp->csect = 0; /* Reset sector address in the cluster */
+ }
+#if _FS_TINY
+ if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */
+ ABORT(fp->fs, FR_DISK_ERR);
+#else
+ if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */
+ if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += fp->csect;
+ cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Write maximum contiguous sectors directly */
+ if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - fp->csect;
+ if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+ if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
+ mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->fs->wflag = 0;
+ }
+#else
+ if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
+ mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ fp->csect += (BYTE)cc; /* Next sector address in the cluster */
+ wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if _FS_TINY
+ if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */
+ if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+ fp->fs->winsect = sect;
+ }
+#else
+ if (fp->dsect != sect) { /* Fill sector buffer with file data */
+ if (fp->fptr < fp->fsize &&
+ disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ fp->csect++; /* Next sector address in the cluster */
+ }
+ wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */
+ if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->fs->wflag = 1;
+#else
+ mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->flag |= FA__DIRTY;
+#endif
+ }
+
+ if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+ fp->flag |= FA__WRITTEN; /* Set file changed flag */
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD tim;
+ BYTE *dir;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
+#if !_FS_TINY /* Write-back dirty buffer */
+ if (fp->flag & FA__DIRTY) {
+ if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+ LEAVE_FF(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ /* Update the directory entry */
+ res = move_window(fp->fs, fp->dir_sect);
+ if (res == FR_OK) {
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
+ ST_WORD(dir+DIR_FstClusLO, fp->org_clust); /* Update start cluster */
+ ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
+ tim = get_fattime(); /* Updated time */
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ fp->flag &= ~FA__WRITTEN;
+ fp->fs->wflag = 1;
+ res = sync(fp->fs);
+ }
+ }
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+ FIL *fp /* Pointer to the file object to be closed */
+)
+{
+ FRESULT res;
+
+
+#if _FS_READONLY
+ res = validate(fp->fs, fp->id);
+ if (res == FR_OK) fp->fs = NULL;
+ LEAVE_FF(fp->fs, res);
+#else
+ res = f_sync(fp);
+ if (res == FR_OK) fp->fs = NULL;
+ return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Current Drive/Directory */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH
+
+FRESULT f_chdrive (
+ BYTE drv /* Drive number */
+)
+{
+ if (drv >= _DRIVES) return FR_INVALID_DRIVE;
+
+ Drive = drv;
+
+ return FR_OK;
+}
+
+
+
+
+FRESULT f_chdir (
+ const XCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) { /* Follow completed */
+ dir = dj.dir; /* Pointer to the entry */
+ if (!dir) {
+ dj.fs->cdir = 0; /* No entry (root dir) */
+ } else {
+ if (dir[DIR_Attr] & AM_DIR) /* Reached to the dir */
+ dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+ else
+ res = FR_NO_PATH; /* Could not reach the dir (it is a file) */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+#endif
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+ FIL *fp, /* Pointer to the file object */
+ DWORD ofs /* File pointer from top of file */
+)
+{
+ FRESULT res;
+ DWORD clst, bcs, nsect, ifptr;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+ && !(fp->flag & FA_WRITE)
+#endif
+ ) ofs = fp->fsize;
+
+ ifptr = fp->fptr;
+ fp->fptr = nsect = 0; fp->csect = 255;
+ if (ofs > 0) {
+ bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
+ if (ifptr > 0 &&
+ (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ ofs -= fp->fptr;
+ clst = fp->curr_clust;
+ } else { /* When seek to back cluster, */
+ clst = fp->org_clust; /* start from the first cluster */
+#if !_FS_READONLY
+ if (clst == 0) { /* If no cluster chain, create a new chain */
+ clst = create_chain(fp->fs, 0);
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->org_clust = clst;
+ }
+#endif
+ fp->curr_clust = clst;
+ }
+ if (clst != 0) {
+ while (ofs > bcs) { /* Cluster following loop */
+#if !_FS_READONLY
+ if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
+ clst = create_chain(fp->fs, clst); /* Force streached if in write mode */
+ if (clst == 0) { /* When disk gets full, clip file size */
+ ofs = bcs; break;
+ }
+ } else
+#endif
+ clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ if (clst <= 1 || clst >= fp->fs->max_clust) ABORT(fp->fs, FR_INT_ERR);
+ fp->curr_clust = clst;
+ fp->fptr += bcs;
+ ofs -= bcs;
+ }
+ fp->fptr += ofs;
+ fp->csect = (BYTE)(ofs / SS(fp->fs)); /* Sector offset in the cluster */
+ if (ofs % SS(fp->fs)) {
+ nsect = clust2sect(fp->fs, clst); /* Current sector */
+ if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+ nsect += fp->csect;
+ fp->csect++;
+ }
+ }
+ }
+ if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */
+ if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = nsect;
+ }
+#if !_FS_READONLY
+ if (fp->fptr > fp->fsize) { /* Set changed flag if the file size is extended */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+ DIR *dj, /* Pointer to directory object to create */
+ const XCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+
+
+ res = chk_mounted(&path, &dj->fs, 0);
+ if (res == FR_OK) {
+ INITBUF((*dj), sfn, lfn);
+ res = follow_path(dj, path); /* Follow the path to the directory */
+ if (res == FR_OK) { /* Follow completed */
+ dir = dj->dir;
+ if (dir) { /* It is not the root dir */
+ if (dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
+ dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+ } else { /* The object is not a directory */
+ res = FR_NO_PATH;
+ }
+ }
+ if (res == FR_OK) {
+ dj->id = dj->fs->id;
+ res = dir_seek(dj, 0); /* Rewind dir */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+ DIR *dj, /* Pointer to the open directory object */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ NAMEBUF(sfn, lfn);
+
+
+ res = validate(dj->fs, dj->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ INITBUF((*dj), sfn, lfn);
+ if (!fno) {
+ res = dir_seek(dj, 0);
+ } else {
+ res = dir_read(dj);
+ if (res == FR_NO_FILE) {
+ dj->sect = 0;
+ res = FR_OK;
+ }
+ if (res == FR_OK) { /* A valid entry is found */
+ get_fileinfo(dj, fno); /* Get the object information */
+ res = dir_next(dj, FALSE); /* Increment index for next */
+ if (res == FR_NO_FILE) {
+ dj->sect = 0;
+ res = FR_OK;
+ }
+ }
+ }
+ }
+
+ LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+ const XCHAR *path, /* Pointer to the file path */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) { /* Follwo completed */
+ if (dj.dir) /* Found an object */
+ get_fileinfo(&dj, fno);
+ else /* It is root dir */
+ res = FR_INVALID_NAME;
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+ const XCHAR *path, /* Pointer to the logical drive number (root dir) */
+ DWORD *nclst, /* Pointer to the variable to return number of free clusters */
+ FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
+)
+{
+ FRESULT res;
+ DWORD n, clst, sect, stat;
+ UINT i;
+ BYTE fat, *p;
+
+
+ /* Get drive number */
+ res = chk_mounted(&path, fatfs, 0);
+ if (res != FR_OK) LEAVE_FF(*fatfs, res);
+
+ /* If number of free cluster is valid, return it without cluster scan. */
+ if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
+ *nclst = (*fatfs)->free_clust;
+ LEAVE_FF(*fatfs, FR_OK);
+ }
+
+ /* Get number of free clusters */
+ fat = (*fatfs)->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clst = 2;
+ do {
+ stat = get_fat(*fatfs, clst);
+ if (stat == 0xFFFFFFFF) LEAVE_FF(*fatfs, FR_DISK_ERR);
+ if (stat == 1) LEAVE_FF(*fatfs, FR_INT_ERR);
+ if (stat == 0) n++;
+ } while (++clst < (*fatfs)->max_clust);
+ } else {
+ clst = (*fatfs)->max_clust;
+ sect = (*fatfs)->fatbase;
+ i = 0; p = 0;
+ do {
+ if (!i) {
+ res = move_window(*fatfs, sect++);
+ if (res != FR_OK)
+ LEAVE_FF(*fatfs, res);
+ p = (*fatfs)->win;
+ i = SS(*fatfs);
+ }
+ if (fat == FS_FAT16) {
+ if (LD_WORD(p) == 0) n++;
+ p += 2; i -= 2;
+ } else {
+ if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+ p += 4; i -= 4;
+ }
+ } while (--clst);
+ }
+ (*fatfs)->free_clust = n;
+ if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
+ *nclst = n;
+
+ LEAVE_FF(*fatfs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD ncl;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+
+ if (fp->fsize > fp->fptr) {
+ fp->fsize = fp->fptr; /* Set file size to current R/W point */
+ fp->flag |= FA__WRITTEN;
+ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
+ res = remove_chain(fp->fs, fp->org_clust);
+ fp->org_clust = 0;
+ } else { /* When truncate a part of the file, remove remaining clusters */
+ ncl = get_fat(fp->fs, fp->curr_clust);
+ res = FR_OK;
+ if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (ncl == 1) res = FR_INT_ERR;
+ if (res == FR_OK && ncl < fp->fs->max_clust) {
+ res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
+ if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+ }
+ }
+ }
+ if (res != FR_OK) fp->flag |= FA__ERROR;
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+ const XCHAR *path /* Pointer to the file or directory path */
+)
+{
+ FRESULT res;
+ DIR dj, sdj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+ DWORD dclst;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
+
+ dir = dj.dir;
+ if (!dir) /* Is it the root directory? */
+ LEAVE_FF(dj.fs, FR_INVALID_NAME);
+ if (dir[DIR_Attr] & AM_RDO) /* Is it a R/O object? */
+ LEAVE_FF(dj.fs, FR_DENIED);
+ dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */
+ if (dclst < 2) LEAVE_FF(dj.fs, FR_INT_ERR);
+ mem_cpy(&sdj, &dj, sizeof(DIR)); /* Check if the sub-dir is empty or not */
+ sdj.sclust = dclst;
+ res = dir_seek(&sdj, 2);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+ res = dir_read(&sdj);
+ if (res == FR_OK) res = FR_DENIED; /* Not empty sub-dir */
+ if (res != FR_NO_FILE) LEAVE_FF(dj.fs, res);
+ }
+
+ res = dir_remove(&dj); /* Remove directory entry */
+ if (res == FR_OK) {
+ if (dclst)
+ res = remove_chain(dj.fs, dclst); /* Remove the cluster chain */
+ if (res == FR_OK) res = sync(dj.fs);
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+ const XCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir, n;
+ DWORD dsect, dclst, pclst, tim;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) res = FR_EXIST; /* Any file or directory is already existing */
+ if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res != FR_NO_FILE) /* Any error occured */
+ LEAVE_FF(dj.fs, res);
+
+ dclst = create_chain(dj.fs, 0); /* Allocate a new cluster for new directory table */
+ res = FR_OK;
+ if (dclst == 0) res = FR_DENIED;
+ if (dclst == 1) res = FR_INT_ERR;
+ if (dclst == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (res == FR_OK)
+ res = move_window(dj.fs, 0);
+ if (res != FR_OK) LEAVE_FF(dj.fs, res);
+ dsect = clust2sect(dj.fs, dclst);
+
+ dir = dj.fs->win; /* Initialize the new directory table */
+ mem_set(dir, 0, SS(dj.fs));
+ mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
+ dir[DIR_Name] = '.';
+ dir[DIR_Attr] = AM_DIR;
+ tim = get_fattime();
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ ST_WORD(dir+DIR_FstClusLO, dclst);
+ ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
+ mem_cpy(dir+32, dir, 32); /* Create ".." entry */
+ dir[33] = '.';
+ pclst = dj.sclust;
+ if (dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase)
+ pclst = 0;
+ ST_WORD(dir+32+DIR_FstClusLO, pclst);
+ ST_WORD(dir+32+DIR_FstClusHI, pclst >> 16);
+ for (n = 0; n < dj.fs->csize; n++) { /* Write dot entries and clear left sectors */
+ dj.fs->winsect = dsect++;
+ dj.fs->wflag = 1;
+ res = move_window(dj.fs, 0);
+ if (res) LEAVE_FF(dj.fs, res);
+ mem_set(dir, 0, SS(dj.fs));
+ }
+
+ res = dir_register(&dj);
+ if (res != FR_OK) {
+ remove_chain(dj.fs, dclst);
+ } else {
+ dir = dj.dir;
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_DWORD(dir+DIR_WrtTime, tim); /* Crated time */
+ ST_WORD(dir+DIR_FstClusLO, dclst); /* Table start cluster */
+ ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change File Attribute */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+ const XCHAR *path, /* Pointer to the file path */
+ BYTE value, /* Attribute bits */
+ BYTE mask /* Attribute mask to change */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Is it a root directory? */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub directory */
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+ const XCHAR *path, /* Pointer to the file/directory name */
+ const FILINFO *fno /* Pointer to the timestamp to be set */
+)
+{
+ FRESULT res;
+ DIR dj;
+ NAMEBUF(sfn, lfn);
+ BYTE *dir;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INITBUF(dj, sfn, lfn);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Root directory */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub-directory */
+ ST_WORD(dir+DIR_WrtTime, fno->ftime);
+ ST_WORD(dir+DIR_WrtDate, fno->fdate);
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+ const XCHAR *path_old, /* Pointer to the old name */
+ const XCHAR *path_new /* Pointer to the new name */
+)
+{
+ FRESULT res;
+ DIR dj_old, dj_new;
+ NAMEBUF(sfn, lfn);
+ BYTE buf[21], *dir;
+ DWORD dw;
+
+
+ INITBUF(dj_old, sfn, lfn);
+ res = chk_mounted(&path_old, &dj_old.fs, 1);
+ if (res == FR_OK) {
+ dj_new.fs = dj_old.fs;
+ res = follow_path(&dj_old, path_old); /* Check old object */
+ if (_FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ }
+ if (res != FR_OK) LEAVE_FF(dj_old.fs, res); /* The old object is not found */
+
+ if (!dj_old.dir) LEAVE_FF(dj_old.fs, FR_NO_FILE); /* Is root dir? */
+ mem_cpy(buf, dj_old.dir+DIR_Attr, 21); /* Save the object information */
+
+ mem_cpy(&dj_new, &dj_old, sizeof(DIR));
+ res = follow_path(&dj_new, path_new); /* Check new object */
+ if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
+ if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
+ res = dir_register(&dj_new); /* Register the new object */
+ if (res == FR_OK) {
+ dir = dj_new.dir; /* Copy object information into new entry */
+ mem_cpy(dir+13, buf+2, 19);
+ dir[DIR_Attr] = buf[0] | AM_ARC;
+ dj_old.fs->wflag = 1;
+ if (dir[DIR_Attr] & AM_DIR) { /* Update .. entry in the directory if needed */
+ dw = clust2sect(dj_new.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
+ if (!dw) {
+ res = FR_INT_ERR;
+ } else {
+ res = move_window(dj_new.fs, dw);
+ dir = dj_new.fs->win+32;
+ if (res == FR_OK && dir[1] == '.') {
+ dw = (dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase) ? 0 : dj_new.sclust;
+ ST_WORD(dir+DIR_FstClusLO, dw);
+ ST_WORD(dir+DIR_FstClusHI, dw >> 16);
+ dj_new.fs->wflag = 1;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&dj_old); /* Remove old entry */
+ if (res == FR_OK)
+ res = sync(dj_old.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj_old.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (Available on only _FS_TINY cfg) */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+ FIL *fp, /* Pointer to the file object */
+ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
+ UINT btr, /* Number of bytes to forward */
+ UINT *bf /* Pointer to number of bytes forwarded */
+)
+{
+ FRESULT res;
+ DWORD remain, clst, sect;
+ UINT rcnt;
+
+
+ *bf = 0;
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check error flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr && (*func)(NULL, 0); /* Repeat until all data transferred or stream becomes busy */
+ fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
+ clst = (fp->fptr == 0) ? /* On the top of the file? */
+ fp->org_clust : get_fat(fp->fs, fp->curr_clust);
+ if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->curr_clust = clst; /* Update current cluster */
+ fp->csect = 0; /* Reset sector address in the cluster */
+ }
+ fp->csect++; /* Next sector address in the cluster */
+ }
+ sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += fp->csect - 1;
+ if (move_window(fp->fs, sect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->dsect = sect;
+ rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
+ if (rcnt > btr) rcnt = btr;
+ rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+ if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR 512 /* Multiple of 32 and <= 2048 */
+#define N_FATS 1 /* 1 or 2 */
+#define MAX_SECTOR 131072000UL /* Maximum partition size */
+#define MIN_SECTOR 2000UL /* Minimum partition size */
+
+
+FRESULT f_mkfs (
+ BYTE drv, /* Logical drive number */
+ BYTE partition, /* Partitioning rule 0:FDISK, 1:SFD */
+ WORD allocsize /* Allocation unit size [bytes] */
+)
+{
+ static const DWORD sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000, 0 };
+ static const WORD cstbl[] = { 32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512 };
+ BYTE fmt, m, *tbl;
+ DWORD b_part, b_fat, b_dir, b_data; /* Area offset (LBA) */
+ DWORD n_part, n_rsv, n_fat, n_dir; /* Area size */
+ DWORD n_clst, d, n;
+ WORD as;
+ FATFS *fs;
+ DSTATUS stat;
+
+
+ /* Check validity of the parameters */
+ if (drv >= _DRIVES) return FR_INVALID_DRIVE;
+ if (partition >= 2) return FR_MKFS_ABORTED;
+
+ /* Check mounted drive and clear work area */
+ fs = FatFs[drv];
+ if (!fs) return FR_NOT_ENABLED;
+ fs->fs_type = 0;
+ drv = LD2PD(drv);
+
+ /* Get disk statics */
+ stat = disk_initialize(drv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512 /* Get disk sector size */
+ if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
+ || SS(fs) > _MAX_SS)
+ return FR_MKFS_ABORTED;
+#endif
+ if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
+ return FR_MKFS_ABORTED;
+ if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
+ b_part = (!partition) ? 63 : 0; /* Boot sector */
+ n_part -= b_part;
+ for (d = 512; d <= 32768U && d != allocsize; d <<= 1) ; /* Check validity of the allocation unit size */
+ if (d != allocsize) allocsize = 0;
+ if (!allocsize) { /* Auto selection of cluster size */
+ d = n_part;
+ for (as = SS(fs); as > 512U; as >>= 1) d >>= 1;
+ for (n = 0; d < sstbl[n]; n++) ;
+ allocsize = cstbl[n];
+ }
+ if (allocsize < SS(fs)) allocsize = SS(fs);
+
+ allocsize /= SS(fs); /* Number of sectors per cluster */
+
+ /* Pre-compute number of clusters and FAT type */
+ n_clst = n_part / allocsize;
+ fmt = FS_FAT12;
+ if (n_clst >= 0xFF5) fmt = FS_FAT16;
+ if (n_clst >= 0xFFF5) fmt = FS_FAT32;
+
+ /* Determine offset and size of FAT structure */
+ switch (fmt) {
+ case FS_FAT12:
+ n_fat = ((n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
+ n_rsv = 1 + partition;
+ n_dir = N_ROOTDIR * 32 / SS(fs);
+ break;
+ case FS_FAT16:
+ n_fat = ((n_clst * 2) + 4 + SS(fs) - 1) / SS(fs);
+ n_rsv = 1 + partition;
+ n_dir = N_ROOTDIR * 32 / SS(fs);
+ break;
+ default:
+ n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+ n_rsv = 33 - partition;
+ n_dir = 0;
+ }
+ b_fat = b_part + n_rsv; /* FATs start sector */
+ b_dir = b_fat + n_fat * N_FATS; /* Directory start sector */
+ b_data = b_dir + n_dir; /* Data start sector */
+
+ /* Align data start sector to erase block boundary (for flash memory media) */
+ if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
+ n = (b_data + n - 1) & ~(n - 1);
+ n_fat += (n - b_data) / N_FATS;
+ /* b_dir and b_data are no longer used below */
+
+ /* Determine number of cluster and final check of validity of the FAT type */
+ n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
+ if ( (fmt == FS_FAT16 && n_clst < 0xFF5)
+ || (fmt == FS_FAT32 && n_clst < 0xFFF5))
+ return FR_MKFS_ABORTED;
+
+ /* Create partition table if needed */
+ if (!partition) {
+ DWORD n_disk = b_part + n_part;
+
+ mem_set(fs->win, 0, SS(fs));
+ tbl = fs->win+MBR_Table;
+ ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */
+ if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
+ n_disk = n_disk / 63 / 255;
+ tbl[7] = (BYTE)n_disk;
+ tbl[6] = (BYTE)((n_disk >> 2) | 63);
+ } else {
+ ST_WORD(&tbl[6], 0xFFFF);
+ }
+ tbl[5] = 254;
+ if (fmt != FS_FAT32) /* System ID */
+ tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
+ else
+ tbl[4] = 0x0c;
+ ST_DWORD(tbl+8, 63); /* Partition start in LBA */
+ ST_DWORD(tbl+12, n_part); /* Partition size in LBA */
+ ST_WORD(tbl+64, 0xAA55); /* Signature */
+ if (disk_write(drv, fs->win, 0, 1) != RES_OK)
+ return FR_DISK_ERR;
+ partition = 0xF8;
+ } else {
+ partition = 0xF0;
+ }
+
+ /* Create boot record */
+ tbl = fs->win; /* Clear buffer */
+ mem_set(tbl, 0, SS(fs));
+ ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */
+ ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */
+ tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */
+ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
+ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
+ ST_WORD(tbl+BPB_RootEntCnt, SS(fs) / 32 * n_dir); /* Number of rootdir entries */
+ if (n_part < 0x10000) { /* Number of total sectors */
+ ST_WORD(tbl+BPB_TotSec16, n_part);
+ } else {
+ ST_DWORD(tbl+BPB_TotSec32, n_part);
+ }
+ tbl[BPB_Media] = partition; /* Media descripter */
+ ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
+ ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
+ ST_DWORD(tbl+BPB_HiddSec, b_part); /* Hidden sectors */
+ n = get_fattime(); /* Use current time as a VSN */
+ if (fmt != FS_FAT32) {
+ ST_DWORD(tbl+BS_VolID, n); /* Volume serial number */
+ ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of secters per FAT */
+ tbl[BS_DrvNum] = 0x80; /* Drive number */
+ tbl[BS_BootSig] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab, "NO NAME FAT ", 19); /* Volume lavel, FAT signature */
+ } else {
+ ST_DWORD(tbl+BS_VolID32, n); /* Volume serial number */
+ ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of secters per FAT */
+ ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory cluster (2) */
+ ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (bs+1) */
+ ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (bs+6) */
+ tbl[BS_DrvNum32] = 0x80; /* Drive number */
+ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab32, "NO NAME FAT32 ", 19); /* Volume lavel, FAT signature */
+ }
+ ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */
+ if (SS(fs) > 512U) {
+ ST_WORD(tbl+SS(fs)-2, 0xAA55);
+ }
+ if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
+ return FR_DISK_ERR;
+ if (fmt == FS_FAT32)
+ disk_write(drv, tbl, b_part+6, 1);
+
+ /* Initialize FAT area */
+ for (m = 0; m < N_FATS; m++) {
+ mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
+ if (fmt != FS_FAT32) {
+ n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+ n |= partition;
+ ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */
+ } else {
+ ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */
+ ST_DWORD(tbl+4, 0xFFFFFFFF);
+ ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
+ }
+ if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ mem_set(tbl, 0, SS(fs)); /* Following FAT entries are filled by zero */
+ for (n = 1; n < n_fat; n++) {
+ if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ }
+ }
+
+ /* Initialize Root directory */
+ m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
+ do {
+ if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ } while (--m);
+
+ /* Create FSInfo record if needed */
+ if (fmt == FS_FAT32) {
+ ST_WORD(tbl+BS_55AA, 0xAA55);
+ ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+ ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+ ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
+ ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
+ disk_write(drv, tbl, b_part+1, 1);
+ disk_write(drv, tbl, b_part+7, 1);
+ }
+
+ return (disk_ioctl(drv, CTRL_SYNC, (void*)NULL) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file */
+/*-----------------------------------------------------------------------*/
+char* f_gets (
+ char* buff, /* Pointer to the string buffer to read */
+ int len, /* Size of string buffer */
+ FIL* fil /* Pointer to the file object */
+)
+{
+ int i = 0;
+ char *p = buff;
+ UINT rc;
+
+
+ while (i < len - 1) { /* Read bytes until buffer gets filled */
+ f_read(fil, p, 1, &rc);
+ if (rc != 1) break; /* Break when no data to read */
+#if _USE_STRFUNC >= 2
+ if (*p == '\r') continue; /* Strip '\r' */
+#endif
+ i++;
+ if (*p++ == '\n') break; /* Break when reached end of line */
+ }
+ *p = 0;
+ return i ? buff : NULL; /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+ int chr, /* A character to be output */
+ FIL* fil /* Ponter to the file object */
+)
+{
+ UINT bw;
+ char c;
+
+
+#if _USE_STRFUNC >= 2
+ if (chr == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
+#endif
+ if (!fil) { /* Special value may be used to switch the destination to any other device */
+ /* put_console(chr); */
+ return chr;
+ }
+ c = (char)chr;
+ f_write(fil, &c, 1, &bw); /* Write a byte to the file */
+ return bw ? chr : EOF; /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+ const char* str, /* Pointer to the string to be output */
+ FIL* fil /* Pointer to the file object */
+)
+{
+ int n;
+
+
+ for (n = 0; *str; str++, n++) {
+ if (f_putc(*str, fil) == EOF) return EOF;
+ }
+ return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+ FIL* fil, /* Pointer to the file object */
+ const char* str, /* Pointer to the format string */
+ ... /* Optional arguments... */
+)
+{
+ va_list arp;
+ UCHAR c, f, r;
+ ULONG val;
+ char s[16];
+ int i, w, res, cc;
+
+
+ va_start(arp, str);
+
+ for (cc = res = 0; cc != EOF; res += cc) {
+ c = *str++;
+ if (c == 0) break; /* End of string */
+ if (c != '%') { /* Non escape cahracter */
+ cc = f_putc(c, fil);
+ if (cc != EOF) cc = 1;
+ continue;
+ }
+ w = f = 0;
+ c = *str++;
+ if (c == '0') { /* Flag: '0' padding */
+ f = 1; c = *str++;
+ }
+ while (c >= '0' && c <= '9') { /* Precision */
+ w = w * 10 + (c - '0');
+ c = *str++;
+ }
+ if (c == 'l') { /* Prefix: Size is long int */
+ f |= 2; c = *str++;
+ }
+ if (c == 's') { /* Type is string */
+ cc = f_puts(va_arg(arp, char*), fil);
+ continue;
+ }
+ if (c == 'c') { /* Type is character */
+ cc = f_putc(va_arg(arp, int), fil);
+ if (cc != EOF) cc = 1;
+ continue;
+ }
+ r = 0;
+ if (c == 'd') r = 10; /* Type is signed decimal */
+ if (c == 'u') r = 10; /* Type is unsigned decimal */
+ if (c == 'X') r = 16; /* Type is unsigned hexdecimal */
+ if (r == 0) break; /* Unknown type */
+ if (f & 2) { /* Get the value */
+ val = (ULONG)va_arg(arp, long);
+ } else {
+ val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
+ }
+ /* Put numeral string */
+ if (c == 'd') {
+ if (val & 0x80000000) {
+ val = 0 - val;
+ f |= 4;
+ }
+ }
+ i = sizeof(s) - 1; s[i] = 0;
+ do {
+ c = (UCHAR)(val % r + '0');
+ if (c > '9') c += 7;
+ s[--i] = c;
+ val /= r;
+ } while (i && val);
+ if (i && (f & 4)) s[--i] = '-';
+ w = sizeof(s) - 1 - w;
+ while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
+ cc = f_puts(&s[i], fil);
+ }
+
+ va_end(arp);
+ return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
diff --git a/Projects/Webserver/Lib/FATFs/ff.h b/Projects/Webserver/Lib/FATFs/ff.h
new file mode 100644
index 000000000..41e136ee5
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/ff.h
@@ -0,0 +1,596 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module include file R0.07e (C)ChaN, 2010
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/ Copyright (C) 2010, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS 0x007E
+
+#include "integer.h" /* Basic integer types */
+#include "ffconf.h" /* FatFs configuration options */
+
+#if _FATFS != _FFCONFIG
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
+#define _DF1S 0x81 /* DBC 1st byte range 1 start */
+#define _DF1E 0x9F /* DBC 1st byte range 1 end */
+#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
+#define _DF2E 0xFC /* DBC 1st byte range 2 end */
+#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
+#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
+#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
+#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0x80
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 949 /* Korean */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x41
+#define _DS1E 0x5A
+#define _DS2S 0x61
+#define _DS2E 0x7A
+#define _DS3S 0x81
+#define _DS3E 0xFE
+
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0xA1
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 437 /* U.S. (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720 /* Arabic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737 /* Greek (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775 /* Baltic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857 /* Turkish (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866 /* Russian (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+ 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
+#define _DF1S 0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+
+/* Character code support macros */
+
+#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
+#define IsLower(c) (((c)>='a')&&((c)<='z'))
+
+#if _DF1S /* DBCS configuration */
+
+#ifdef _DF2S /* Two 1st byte areas */
+#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else /* One 1st byte area */
+#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S /* Three 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else /* Two 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else /* SBCS configuration */
+
+#define IsDBCS1(c) 0
+#define IsDBCS2(c) 0
+
+#endif /* _DF1S */
+
+
+
+/* Definitions corresponds to multi partition */
+
+#if _MULTI_PARTITION /* Multiple partition configuration */
+
+typedef struct _PARTITION {
+ BYTE pd; /* Physical drive# */
+ BYTE pt; /* Partition # (0-3) */
+} PARTITION;
+
+extern
+const PARTITION Drives[]; /* Logical drive# to physical location conversion table */
+#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
+#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
+
+#else /* Single partition configuration */
+
+#define LD2PD(drv) (drv) /* Physical drive# is equal to the logical drive# */
+#define LD2PT(drv) 0 /* Always mounts the 1st partition */
+
+#endif
+
+
+
+/* Definitions corresponds to multiple sector size */
+
+#if _MAX_SS == 512 /* Single sector size */
+#define SS(fs) 512U
+
+#elif _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096 /* Multiple sector size */
+#define SS(fs) ((fs)->s_size)
+
+#else
+#error Sector size must be 512, 1024, 2048 or 4096.
+
+#endif
+
+
+
+/* Type of file name on FatFs API */
+
+#if _LFN_UNICODE && _USE_LFN
+typedef WCHAR XCHAR; /* Unicode */
+#else
+typedef char XCHAR; /* SBCS, DBCS */
+#endif
+
+
+
+/* File system object structure */
+
+typedef struct _FATFS_ {
+ BYTE fs_type; /* FAT sub type */
+ BYTE drive; /* Physical drive number */
+ BYTE csize; /* Number of sectors per cluster */
+ BYTE n_fats; /* Number of FAT copies */
+ BYTE wflag; /* win[] dirty flag (1:must be written back) */
+ BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
+ WORD id; /* File system mount ID */
+ WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */
+#if _FS_REENTRANT
+ _SYNC_t sobj; /* Identifier of sync object */
+#endif
+#if _MAX_SS != 512
+ WORD s_size; /* Sector size */
+#endif
+#if !_FS_READONLY
+ DWORD last_clust; /* Last allocated cluster */
+ DWORD free_clust; /* Number of free clusters */
+ DWORD fsi_sector; /* fsinfo sector */
+#endif
+#if _FS_RPATH
+ DWORD cdir; /* Current directory (0:root)*/
+#endif
+ DWORD sects_fat; /* Sectors per fat */
+ DWORD max_clust; /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
+ DWORD fatbase; /* FAT start sector */
+ DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */
+ DWORD database; /* Data start sector */
+ DWORD winsect; /* Current sector appearing in the win[] */
+ BYTE win[_MAX_SS];/* Disk access window for Directory/FAT */
+} FATFS;
+
+
+
+/* Directory object structure */
+
+typedef struct _DIR_ {
+ FATFS* fs; /* Pointer to the owner file system object */
+ WORD id; /* Owner file system mount ID */
+ WORD index; /* Current read/write index number */
+ DWORD sclust; /* Table start cluster (0:Static table) */
+ DWORD clust; /* Current cluster */
+ DWORD sect; /* Current sector */
+ BYTE* dir; /* Pointer to the current SFN entry in the win[] */
+ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _USE_LFN
+ WCHAR* lfn; /* Pointer to the LFN working buffer */
+ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} DIR;
+
+
+
+/* File object structure */
+
+typedef struct _FIL_ {
+ FATFS* fs; /* Pointer to the owner file system object */
+ WORD id; /* Owner file system mount ID */
+ BYTE flag; /* File status flags */
+ BYTE csect; /* Sector address in the cluster */
+ DWORD fptr; /* File R/W pointer */
+ DWORD fsize; /* File size */
+ DWORD org_clust; /* File start cluster */
+ DWORD curr_clust; /* Current cluster */
+ DWORD dsect; /* Current data sector */
+#if !_FS_READONLY
+ DWORD dir_sect; /* Sector containing the directory entry */
+ BYTE* dir_ptr; /* Ponter to the directory entry in the window */
+#endif
+#if !_FS_TINY
+ BYTE buf[_MAX_SS];/* File R/W buffer */
+#endif
+} FIL;
+
+
+
+/* File status structure */
+
+typedef struct _FILINFO_ {
+ DWORD fsize; /* File size */
+ WORD fdate; /* Last modified date */
+ WORD ftime; /* Last modified time */
+ BYTE fattrib; /* Attribute */
+ char fname[13]; /* Short file name (8.3 format) */
+#if _USE_LFN
+ XCHAR* lfname; /* Pointer to the LFN buffer */
+ int lfsize; /* Size of LFN buffer [chrs] */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+ FR_OK = 0, /* 0 */
+ FR_DISK_ERR, /* 1 */
+ FR_INT_ERR, /* 2 */
+ FR_NOT_READY, /* 3 */
+ FR_NO_FILE, /* 4 */
+ FR_NO_PATH, /* 5 */
+ FR_INVALID_NAME, /* 6 */
+ FR_DENIED, /* 7 */
+ FR_EXIST, /* 8 */
+ FR_INVALID_OBJECT, /* 9 */
+ FR_WRITE_PROTECTED, /* 10 */
+ FR_INVALID_DRIVE, /* 11 */
+ FR_NOT_ENABLED, /* 12 */
+ FR_NO_FILESYSTEM, /* 13 */
+ FR_MKFS_ABORTED, /* 14 */
+ FR_TIMEOUT /* 15 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface */
+
+FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const XCHAR*, BYTE); /* Open or create a file */
+FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
+FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
+FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
+FRESULT f_close (FIL*); /* Close an open file object */
+FRESULT f_opendir (DIR*, const XCHAR*); /* Open an existing directory */
+FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
+FRESULT f_stat (const XCHAR*, FILINFO*); /* Get file status */
+FRESULT f_getfree (const XCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
+FRESULT f_truncate (FIL*); /* Truncate file */
+FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
+FRESULT f_unlink (const XCHAR*); /* Delete an existing file or directory */
+FRESULT f_mkdir (const XCHAR*); /* Create a new directory */
+FRESULT f_chmod (const XCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */
+FRESULT f_utime (const XCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
+FRESULT f_rename (const XCHAR*, const XCHAR*); /* Rename/Move a file or directory */
+FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
+FRESULT f_chdir (const XCHAR*); /* Change current directory */
+FRESULT f_chdrive (BYTE); /* Change current drive */
+
+#if _USE_STRFUNC
+int f_putc (int, FIL*); /* Put a character to the file */
+int f_puts (const char*, FIL*); /* Put a string to the file */
+int f_printf (FIL*, const char*, ...); /* Put a formatted string to the file */
+char* f_gets (char*, int, FIL*); /* Get a string from the file */
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#ifndef EOF
+#define EOF -1
+#endif
+#endif
+
+
+
+/*--------------------------------------------------------------*/
+/* User defined functions */
+
+/* Real time clock */
+#if !_FS_READONLY
+DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
+ /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
+#endif
+
+/* Unicode - OEM code conversion */
+#if _USE_LFN
+WCHAR ff_convert (WCHAR, UINT);
+WCHAR ff_wtoupper (WCHAR);
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+BOOL ff_cre_syncobj(BYTE, _SYNC_t*);
+BOOL ff_del_syncobj(_SYNC_t);
+BOOL ff_req_grant(_SYNC_t);
+void ff_rel_grant(_SYNC_t);
+#endif
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define FA_READ 0x01
+#define FA_OPEN_EXISTING 0x00
+#if _FS_READONLY == 0
+#define FA_WRITE 0x02
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA__WRITTEN 0x20
+#define FA__DIRTY 0x40
+#endif
+#define FA__ERROR 0x80
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+
+
+/* File attribute bits for directory entry */
+
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+#define AM_MASK 0x3F /* Mask of defined bits */
+
+
+/* FatFs refers the members in the FAT structures with byte offset instead
+/ of structure member because there are incompatibility of the packing option
+/ between various compilers. */
+
+#define BS_jmpBoot 0
+#define BS_OEMName 3
+#define BPB_BytsPerSec 11
+#define BPB_SecPerClus 13
+#define BPB_RsvdSecCnt 14
+#define BPB_NumFATs 16
+#define BPB_RootEntCnt 17
+#define BPB_TotSec16 19
+#define BPB_Media 21
+#define BPB_FATSz16 22
+#define BPB_SecPerTrk 24
+#define BPB_NumHeads 26
+#define BPB_HiddSec 28
+#define BPB_TotSec32 32
+#define BS_55AA 510
+
+#define BS_DrvNum 36
+#define BS_BootSig 38
+#define BS_VolID 39
+#define BS_VolLab 43
+#define BS_FilSysType 54
+
+#define BPB_FATSz32 36
+#define BPB_ExtFlags 40
+#define BPB_FSVer 42
+#define BPB_RootClus 44
+#define BPB_FSInfo 48
+#define BPB_BkBootSec 50
+#define BS_DrvNum32 64
+#define BS_BootSig32 66
+#define BS_VolID32 67
+#define BS_VolLab32 71
+#define BS_FilSysType32 82
+
+#define FSI_LeadSig 0
+#define FSI_StrucSig 484
+#define FSI_Free_Count 488
+#define FSI_Nxt_Free 492
+
+#define MBR_Table 446
+
+#define DIR_Name 0
+#define DIR_Attr 11
+#define DIR_NTres 12
+#define DIR_CrtTime 14
+#define DIR_CrtDate 16
+#define DIR_FstClusHI 20
+#define DIR_WrtTime 22
+#define DIR_WrtDate 24
+#define DIR_FstClusLO 26
+#define DIR_FileSize 28
+#define LDIR_Ord 0
+#define LDIR_Attr 11
+#define LDIR_Type 12
+#define LDIR_Chksum 13
+#define LDIR_FstClusLO 26
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros */
+
+#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else /* Use byte-by-byte access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+
+#endif /* _FATFS */
diff --git a/Projects/Webserver/Lib/FATFs/ff.lst b/Projects/Webserver/Lib/FATFs/ff.lst
new file mode 100644
index 000000000..2a8f9fc4e
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/ff.lst
@@ -0,0 +1,3062 @@
+ 1 .file "ff.c"
+ 2 __SREG__ = 0x3f
+ 3 __SP_H__ = 0x3e
+ 4 __SP_L__ = 0x3d
+ 5 __CCP__ = 0x34
+ 6 __tmp_reg__ = 0
+ 7 __zero_reg__ = 1
+ 15 .Ltext0:
+ 16 .section .text.clust2sect,"ax",@progbits
+ 17 .global clust2sect
+ 19 clust2sect:
+ 20 .LFB60:
+ 21 .LSM0:
+ 22 .LVL0:
+ 23 0000 EF92 push r14
+ 24 0002 FF92 push r15
+ 25 0004 0F93 push r16
+ 26 0006 1F93 push r17
+ 27 0008 CF93 push r28
+ 28 000a DF93 push r29
+ 29 /* prologue: function */
+ 30 /* frame size = 0 */
+ 31 000c EC01 movw r28,r24
+ 32 000e 7A01 movw r14,r20
+ 33 0010 8B01 movw r16,r22
+ 34 .LSM1:
+ 35 0012 8EEF ldi r24,lo8(-2)
+ 36 0014 9FEF ldi r25,hi8(-2)
+ 37 0016 AFEF ldi r26,hlo8(-2)
+ 38 0018 BFEF ldi r27,hhi8(-2)
+ 39 .LVL1:
+ 40 001a E80E add r14,r24
+ 41 001c F91E adc r15,r25
+ 42 001e 0A1F adc r16,r26
+ 43 0020 1B1F adc r17,r27
+ 44 .LVL2:
+ 45 .LSM2:
+ 46 0022 8E85 ldd r24,Y+14
+ 47 0024 9F85 ldd r25,Y+15
+ 48 0026 A889 ldd r26,Y+16
+ 49 0028 B989 ldd r27,Y+17
+ 50 002a 0297 sbiw r24,2
+ 51 002c A109 sbc r26,__zero_reg__
+ 52 002e B109 sbc r27,__zero_reg__
+ 53 0030 E816 cp r14,r24
+ 54 0032 F906 cpc r15,r25
+ 55 0034 0A07 cpc r16,r26
+ 56 0036 1B07 cpc r17,r27
+ 57 0038 00F0 brlo .L2
+ 58 003a 20E0 ldi r18,lo8(0)
+ 59 003c 30E0 ldi r19,hi8(0)
+ 60 003e 40E0 ldi r20,hlo8(0)
+ 61 0040 50E0 ldi r21,hhi8(0)
+ 62 0042 00C0 rjmp .L3
+ 63 .L2:
+ 64 .LSM3:
+ 65 0044 2A81 ldd r18,Y+2
+ 66 0046 30E0 ldi r19,lo8(0)
+ 67 0048 40E0 ldi r20,lo8(0)
+ 68 004a 50E0 ldi r21,hi8(0)
+ 69 004c C801 movw r24,r16
+ 70 004e B701 movw r22,r14
+ 71 0050 0E94 0000 call __mulsi3
+ 72 0054 9B01 movw r18,r22
+ 73 0056 AC01 movw r20,r24
+ 74 0058 8A8D ldd r24,Y+26
+ 75 005a 9B8D ldd r25,Y+27
+ 76 005c AC8D ldd r26,Y+28
+ 77 005e BD8D ldd r27,Y+29
+ 78 0060 280F add r18,r24
+ 79 0062 391F adc r19,r25
+ 80 0064 4A1F adc r20,r26
+ 81 0066 5B1F adc r21,r27
+ 82 .L3:
+ 83 .LSM4:
+ 84 0068 B901 movw r22,r18
+ 85 006a CA01 movw r24,r20
+ 86 /* epilogue start */
+ 87 006c DF91 pop r29
+ 88 006e CF91 pop r28
+ 89 .LVL3:
+ 90 0070 1F91 pop r17
+ 91 0072 0F91 pop r16
+ 92 0074 FF90 pop r15
+ 93 0076 EF90 pop r14
+ 94 .LVL4:
+ 95 0078 0895 ret
+ 96 .LFE60:
+ 98 .section .text.f_mount,"ax",@progbits
+ 99 .global f_mount
+ 101 f_mount:
+ 102 .LFB69:
+ 103 .LSM5:
+ 104 .LVL5:
+ 105 /* prologue: function */
+ 106 /* frame size = 0 */
+ 107 0000 DB01 movw r26,r22
+ 108 .LSM6:
+ 109 0002 8823 tst r24
+ 110 0004 01F0 breq .L6
+ 111 .LVL6:
+ 112 0006 8BE0 ldi r24,lo8(11)
+ 113 .LVL7:
+ 114 0008 0895 ret
+ 115 .LVL8:
+ 116 .L6:
+ 117 .LSM7:
+ 118 000a E091 0000 lds r30,FatFs
+ 119 000e F091 0000 lds r31,(FatFs)+1
+ 120 .LVL9:
+ 121 .LSM8:
+ 122 0012 3097 sbiw r30,0
+ 123 0014 01F0 breq .L8
+ 124 .LSM9:
+ 125 0016 1082 st Z,__zero_reg__
+ 126 .L8:
+ 127 .LSM10:
+ 128 0018 1097 sbiw r26,0
+ 129 001a 01F0 breq .L9
+ 130 .LSM11:
+ 131 001c 1C92 st X,__zero_reg__
+ 132 .L9:
+ 133 .LSM12:
+ 134 001e B093 0000 sts (FatFs)+1,r27
+ 135 0022 A093 0000 sts FatFs,r26
+ 136 0026 80E0 ldi r24,lo8(0)
+ 137 .LVL10:
+ 138 .LSM13:
+ 139 0028 0895 ret
+ 140 .LFE69:
+ 142 .section .text.validate,"ax",@progbits
+ 144 validate:
+ 145 .LFB68:
+ 146 .LSM14:
+ 147 .LVL11:
+ 148 /* prologue: function */
+ 149 /* frame size = 0 */
+ 150 0000 FC01 movw r30,r24
+ 151 .LSM15:
+ 152 0002 0097 sbiw r24,0
+ 153 0004 01F0 breq .L12
+ 154 0006 8081 ld r24,Z
+ 155 .LVL12:
+ 156 0008 8823 tst r24
+ 157 000a 01F0 breq .L12
+ 158 000c 8681 ldd r24,Z+6
+ 159 000e 9781 ldd r25,Z+7
+ 160 0010 8617 cp r24,r22
+ 161 0012 9707 cpc r25,r23
+ 162 0014 01F4 brne .L12
+ 163 .LSM16:
+ 164 0016 8181 ldd r24,Z+1
+ 165 0018 0E94 0000 call disk_status
+ 166 .LVL13:
+ 167 001c 80FD sbrc r24,0
+ 168 001e 00C0 rjmp .L13
+ 169 0020 80E0 ldi r24,lo8(0)
+ 170 0022 0895 ret
+ 171 .L13:
+ 172 0024 83E0 ldi r24,lo8(3)
+ 173 0026 0895 ret
+ 174 .LVL14:
+ 175 .L12:
+ 176 0028 89E0 ldi r24,lo8(9)
+ 177 .LSM17:
+ 178 002a 0895 ret
+ 179 .LFE68:
+ 181 .section .text.f_close,"ax",@progbits
+ 182 .global f_close
+ 184 f_close:
+ 185 .LFB72:
+ 186 .LSM18:
+ 187 .LVL15:
+ 188 0000 CF93 push r28
+ 189 0002 DF93 push r29
+ 190 /* prologue: function */
+ 191 /* frame size = 0 */
+ 192 0004 EC01 movw r28,r24
+ 193 .LSM19:
+ 194 0006 6A81 ldd r22,Y+2
+ 195 0008 7B81 ldd r23,Y+3
+ 196 000a 8881 ld r24,Y
+ 197 000c 9981 ldd r25,Y+1
+ 198 .LVL16:
+ 199 000e 0E94 0000 call validate
+ 200 .LSM20:
+ 201 0012 8823 tst r24
+ 202 .LVL17:
+ 203 0014 01F4 brne .L17
+ 204 0016 1982 std Y+1,__zero_reg__
+ 205 0018 1882 st Y,__zero_reg__
+ 206 .L17:
+ 207 .LVL18:
+ 208 /* epilogue start */
+ 209 .LSM21:
+ 210 001a DF91 pop r29
+ 211 001c CF91 pop r28
+ 212 .LVL19:
+ 213 001e 0895 ret
+ 214 .LFE72:
+ 216 .section .text.move_window,"ax",@progbits
+ 218 move_window:
+ 219 .LFB58:
+ 220 .LSM22:
+ 221 .LVL20:
+ 222 0000 CF92 push r12
+ 223 0002 DF92 push r13
+ 224 0004 EF92 push r14
+ 225 0006 FF92 push r15
+ 226 0008 0F93 push r16
+ 227 000a CF93 push r28
+ 228 000c DF93 push r29
+ 229 /* prologue: function */
+ 230 /* frame size = 0 */
+ 231 000e EC01 movw r28,r24
+ 232 0010 6A01 movw r12,r20
+ 233 0012 7B01 movw r14,r22
+ 234 .LSM23:
+ 235 0014 8E8D ldd r24,Y+30
+ 236 0016 9F8D ldd r25,Y+31
+ 237 0018 A8A1 ldd r26,Y+32
+ 238 001a B9A1 ldd r27,Y+33
+ 239 .LVL21:
+ 240 001c 8417 cp r24,r20
+ 241 001e 9507 cpc r25,r21
+ 242 0020 A607 cpc r26,r22
+ 243 0022 B707 cpc r27,r23
+ 244 0024 01F0 breq .L20
+ 245 .LSM24:
+ 246 0026 4115 cp r20,__zero_reg__
+ 247 0028 5105 cpc r21,__zero_reg__
+ 248 002a 6105 cpc r22,__zero_reg__
+ 249 002c 7105 cpc r23,__zero_reg__
+ 250 002e 01F0 breq .L20
+ 251 .LSM25:
+ 252 0030 BE01 movw r22,r28
+ 253 0032 6E5D subi r22,lo8(-(34))
+ 254 0034 7F4F sbci r23,hi8(-(34))
+ 255 0036 8981 ldd r24,Y+1
+ 256 0038 A701 movw r20,r14
+ 257 003a 9601 movw r18,r12
+ 258 003c 01E0 ldi r16,lo8(1)
+ 259 003e 0E94 0000 call disk_read
+ 260 .LVL22:
+ 261 0042 8823 tst r24
+ 262 0044 01F0 breq .L21
+ 263 0046 81E0 ldi r24,lo8(1)
+ 264 0048 00C0 rjmp .L22
+ 265 .L21:
+ 266 .LSM26:
+ 267 004a CE8E std Y+30,r12
+ 268 004c DF8E std Y+31,r13
+ 269 004e E8A2 std Y+32,r14
+ 270 0050 F9A2 std Y+33,r15
+ 271 .LVL23:
+ 272 .L20:
+ 273 0052 80E0 ldi r24,lo8(0)
+ 274 .L22:
+ 275 /* epilogue start */
+ 276 .LSM27:
+ 277 0054 DF91 pop r29
+ 278 0056 CF91 pop r28
+ 279 .LVL24:
+ 280 0058 0F91 pop r16
+ 281 005a FF90 pop r15
+ 282 005c EF90 pop r14
+ 283 005e DF90 pop r13
+ 284 0060 CF90 pop r12
+ 285 .LVL25:
+ 286 0062 0895 ret
+ 287 .LFE58:
+ 289 .section .text.get_fat,"ax",@progbits
+ 290 .global get_fat
+ 292 get_fat:
+ 293 .LFB59:
+ 294 .LSM28:
+ 295 .LVL26:
+ 296 0000 7F92 push r7
+ 297 0002 8F92 push r8
+ 298 0004 9F92 push r9
+ 299 0006 AF92 push r10
+ 300 0008 BF92 push r11
+ 301 000a CF92 push r12
+ 302 000c DF92 push r13
+ 303 000e EF92 push r14
+ 304 0010 FF92 push r15
+ 305 0012 0F93 push r16
+ 306 0014 1F93 push r17
+ 307 0016 CF93 push r28
+ 308 0018 DF93 push r29
+ 309 /* prologue: function */
+ 310 /* frame size = 0 */
+ 311 001a 4C01 movw r8,r24
+ 312 001c 7A01 movw r14,r20
+ 313 001e 8B01 movw r16,r22
+ 314 .LSM29:
+ 315 0020 4230 cpi r20,lo8(2)
+ 316 0022 5105 cpc r21,__zero_reg__
+ 317 0024 6105 cpc r22,__zero_reg__
+ 318 0026 7105 cpc r23,__zero_reg__
+ 319 .LVL27:
+ 320 0028 00F4 brsh .+2
+ 321 002a 00C0 rjmp .L25
+ 322 002c F401 movw r30,r8
+ 323 002e 8685 ldd r24,Z+14
+ 324 0030 9785 ldd r25,Z+15
+ 325 0032 A089 ldd r26,Z+16
+ 326 0034 B189 ldd r27,Z+17
+ 327 0036 4817 cp r20,r24
+ 328 0038 5907 cpc r21,r25
+ 329 003a 6A07 cpc r22,r26
+ 330 003c 7B07 cpc r23,r27
+ 331 003e 00F0 brlo .+2
+ 332 0040 00C0 rjmp .L25
+ 333 .LSM30:
+ 334 0042 A288 ldd r10,Z+18
+ 335 0044 B388 ldd r11,Z+19
+ 336 0046 C488 ldd r12,Z+20
+ 337 0048 D588 ldd r13,Z+21
+ 338 .LVL28:
+ 339 .LSM31:
+ 340 004a 8081 ld r24,Z
+ 341 004c 8230 cpi r24,lo8(2)
+ 342 004e 01F4 brne .+2
+ 343 0050 00C0 rjmp .L28
+ 344 0052 8330 cpi r24,lo8(3)
+ 345 0054 01F4 brne .+2
+ 346 0056 00C0 rjmp .L29
+ 347 0058 8130 cpi r24,lo8(1)
+ 348 005a 01F0 breq .+2
+ 349 005c 00C0 rjmp .L26
+ 350 .LSM32:
+ 351 005e EA01 movw r28,r20
+ 352 .LVL29:
+ 353 0060 D695 lsr r29
+ 354 0062 C795 ror r28
+ 355 .LVL30:
+ 356 0064 C40F add r28,r20
+ 357 0066 D51F adc r29,r21
+ 358 .LSM33:
+ 359 0068 AE01 movw r20,r28
+ 360 .LVL31:
+ 361 006a 452F mov r20,r21
+ 362 006c 5527 clr r21
+ 363 006e 4695 lsr r20
+ 364 0070 60E0 ldi r22,lo8(0)
+ 365 0072 70E0 ldi r23,hi8(0)
+ 366 0074 4A0D add r20,r10
+ 367 0076 5B1D adc r21,r11
+ 368 0078 6C1D adc r22,r12
+ 369 007a 7D1D adc r23,r13
+ 370 007c C401 movw r24,r8
+ 371 007e 0E94 0000 call move_window
+ 372 0082 8823 tst r24
+ 373 0084 01F0 breq .+2
+ 374 0086 00C0 rjmp .L26
+ 375 .LSM34:
+ 376 0088 FE01 movw r30,r28
+ 377 008a F170 andi r31,hi8(511)
+ 378 008c E80D add r30,r8
+ 379 008e F91D adc r31,r9
+ 380 0090 72A0 ldd r7,Z+34
+ 381 0092 2196 adiw r28,1
+ 382 .LVL32:
+ 383 .LSM35:
+ 384 0094 AE01 movw r20,r28
+ 385 0096 452F mov r20,r21
+ 386 0098 5527 clr r21
+ 387 009a 4695 lsr r20
+ 388 009c 60E0 ldi r22,lo8(0)
+ 389 009e 70E0 ldi r23,hi8(0)
+ 390 00a0 4A0D add r20,r10
+ 391 00a2 5B1D adc r21,r11
+ 392 00a4 6C1D adc r22,r12
+ 393 00a6 7D1D adc r23,r13
+ 394 00a8 C401 movw r24,r8
+ 395 00aa 0E94 0000 call move_window
+ 396 00ae 8823 tst r24
+ 397 00b0 01F0 breq .+2
+ 398 00b2 00C0 rjmp .L26
+ 399 .LSM36:
+ 400 00b4 672D mov r22,r7
+ 401 .LVL33:
+ 402 00b6 70E0 ldi r23,lo8(0)
+ 403 .LVL34:
+ 404 .LSM37:
+ 405 00b8 D170 andi r29,hi8(511)
+ 406 00ba C80D add r28,r8
+ 407 00bc D91D adc r29,r9
+ 408 00be 9AA1 ldd r25,Y+34
+ 409 00c0 80E0 ldi r24,lo8(0)
+ 410 00c2 682B or r22,r24
+ 411 00c4 792B or r23,r25
+ 412 .LVL35:
+ 413 .LSM38:
+ 414 00c6 C701 movw r24,r14
+ 415 .LVL36:
+ 416 00c8 8170 andi r24,lo8(1)
+ 417 00ca 9070 andi r25,hi8(1)
+ 418 00cc 892B or r24,r25
+ 419 00ce 01F0 breq .L30
+ 420 00d0 44E0 ldi r20,4
+ 421 00d2 7695 1: lsr r23
+ 422 00d4 6795 ror r22
+ 423 00d6 4A95 dec r20
+ 424 00d8 01F4 brne 1b
+ 425 00da 9B01 movw r18,r22
+ 426 00dc 00C0 rjmp .L33
+ 427 .L30:
+ 428 00de 9B01 movw r18,r22
+ 429 00e0 40E0 ldi r20,lo8(0)
+ 430 00e2 50E0 ldi r21,hi8(0)
+ 431 00e4 3F70 andi r19,hi8(4095)
+ 432 00e6 4070 andi r20,hlo8(4095)
+ 433 00e8 5070 andi r21,hhi8(4095)
+ 434 00ea 00C0 rjmp .L31
+ 435 .LVL37:
+ 436 .L28:
+ 437 .LSM39:
+ 438 00ec 452F mov r20,r21
+ 439 00ee 562F mov r21,r22
+ 440 00f0 672F mov r22,r23
+ 441 00f2 7727 clr r23
+ 442 .LVL38:
+ 443 00f4 4A0D add r20,r10
+ 444 00f6 5B1D adc r21,r11
+ 445 00f8 6C1D adc r22,r12
+ 446 00fa 7D1D adc r23,r13
+ 447 00fc C401 movw r24,r8
+ 448 00fe 0E94 0000 call move_window
+ 449 0102 8823 tst r24
+ 450 0104 01F4 brne .L26
+ 451 .LSM40:
+ 452 0106 F701 movw r30,r14
+ 453 .LVL39:
+ 454 0108 EE0F lsl r30
+ 455 010a FF1F rol r31
+ 456 010c F170 andi r31,hi8(511)
+ 457 010e E80D add r30,r8
+ 458 0110 F91D adc r31,r9
+ 459 0112 82A1 ldd r24,Z+34
+ 460 0114 93A1 ldd r25,Z+35
+ 461 0116 9C01 movw r18,r24
+ 462 .LVL40:
+ 463 .L33:
+ 464 0118 40E0 ldi r20,lo8(0)
+ 465 011a 50E0 ldi r21,hi8(0)
+ 466 011c 00C0 rjmp .L31
+ 467 .LVL41:
+ 468 .L29:
+ 469 .LSM41:
+ 470 011e 97E0 ldi r25,7
+ 471 0120 7695 1: lsr r23
+ 472 0122 6795 ror r22
+ 473 0124 5795 ror r21
+ 474 0126 4795 ror r20
+ 475 0128 9A95 dec r25
+ 476 012a 01F4 brne 1b
+ 477 .LVL42:
+ 478 012c 4A0D add r20,r10
+ 479 012e 5B1D adc r21,r11
+ 480 0130 6C1D adc r22,r12
+ 481 0132 7D1D adc r23,r13
+ 482 0134 C401 movw r24,r8
+ 483 0136 0E94 0000 call move_window
+ 484 013a 8823 tst r24
+ 485 013c 01F4 brne .L26
+ 486 .LSM42:
+ 487 013e F701 movw r30,r14
+ 488 .LVL43:
+ 489 0140 EE0F lsl r30
+ 490 0142 FF1F rol r31
+ 491 0144 EE0F lsl r30
+ 492 0146 FF1F rol r31
+ 493 0148 F170 andi r31,hi8(511)
+ 494 014a E80D add r30,r8
+ 495 014c F91D adc r31,r9
+ 496 014e 22A1 ldd r18,Z+34
+ 497 0150 33A1 ldd r19,Z+35
+ 498 0152 44A1 ldd r20,Z+36
+ 499 0154 55A1 ldd r21,Z+37
+ 500 0156 5F70 andi r21,hhi8(268435455)
+ 501 0158 00C0 rjmp .L31
+ 502 .LVL44:
+ 503 .L25:
+ 504 015a 21E0 ldi r18,lo8(1)
+ 505 015c 30E0 ldi r19,hi8(1)
+ 506 015e 40E0 ldi r20,hlo8(1)
+ 507 0160 50E0 ldi r21,hhi8(1)
+ 508 0162 00C0 rjmp .L31
+ 509 .LVL45:
+ 510 .L26:
+ 511 0164 2FEF ldi r18,lo8(-1)
+ 512 0166 3FEF ldi r19,hi8(-1)
+ 513 0168 4FEF ldi r20,hlo8(-1)
+ 514 016a 5FEF ldi r21,hhi8(-1)
+ 515 .LVL46:
+ 516 .L31:
+ 517 .LSM43:
+ 518 016c B901 movw r22,r18
+ 519 .LVL47:
+ 520 016e CA01 movw r24,r20
+ 521 /* epilogue start */
+ 522 0170 DF91 pop r29
+ 523 0172 CF91 pop r28
+ 524 .LVL48:
+ 525 0174 1F91 pop r17
+ 526 0176 0F91 pop r16
+ 527 0178 FF90 pop r15
+ 528 017a EF90 pop r14
+ 529 .LVL49:
+ 530 017c DF90 pop r13
+ 531 017e CF90 pop r12
+ 532 0180 BF90 pop r11
+ 533 0182 AF90 pop r10
+ 534 .LVL50:
+ 535 0184 9F90 pop r9
+ 536 0186 8F90 pop r8
+ 537 .LVL51:
+ 538 0188 7F90 pop r7
+ 539 018a 0895 ret
+ 540 .LFE59:
+ 542 .section .text.f_lseek,"ax",@progbits
+ 543 .global f_lseek
+ 545 f_lseek:
+ 546 .LFB73:
+ 547 .LSM44:
+ 548 .LVL52:
+ 549 0000 2F92 push r2
+ 550 0002 3F92 push r3
+ 551 0004 4F92 push r4
+ 552 0006 5F92 push r5
+ 553 0008 6F92 push r6
+ 554 000a 7F92 push r7
+ 555 000c 8F92 push r8
+ 556 000e 9F92 push r9
+ 557 0010 AF92 push r10
+ 558 0012 BF92 push r11
+ 559 0014 CF92 push r12
+ 560 0016 DF92 push r13
+ 561 0018 EF92 push r14
+ 562 001a FF92 push r15
+ 563 001c 0F93 push r16
+ 564 001e 1F93 push r17
+ 565 0020 DF93 push r29
+ 566 0022 CF93 push r28
+ 567 0024 00D0 rcall .
+ 568 0026 0F92 push __tmp_reg__
+ 569 0028 CDB7 in r28,__SP_L__
+ 570 002a DEB7 in r29,__SP_H__
+ 571 /* prologue: function */
+ 572 /* frame size = 3 */
+ 573 002c 9B83 std Y+3,r25
+ 574 002e 8A83 std Y+2,r24
+ 575 0030 E42E mov r14,r20
+ 576 0032 D52E mov r13,r21
+ 577 .LVL53:
+ 578 0034 C62E mov r12,r22
+ 579 .LVL54:
+ 580 0036 B72E mov r11,r23
+ 581 .LVL55:
+ 582 .LSM45:
+ 583 0038 DC01 movw r26,r24
+ 584 003a 1296 adiw r26,2
+ 585 003c 6D91 ld r22,X+
+ 586 003e 7C91 ld r23,X
+ 587 0040 1397 sbiw r26,2+1
+ 588 .LVL56:
+ 589 0042 8D91 ld r24,X+
+ 590 0044 9C91 ld r25,X
+ 591 .LVL57:
+ 592 0046 0E94 0000 call validate
+ 593 .LVL58:
+ 594 004a 8983 std Y+1,r24
+ 595 .LVL59:
+ 596 .LSM46:
+ 597 004c 8823 tst r24
+ 598 004e 01F0 breq .+2
+ 599 0050 00C0 rjmp .L35
+ 600 .LSM47:
+ 601 0052 EA81 ldd r30,Y+2
+ 602 0054 FB81 ldd r31,Y+3
+ 603 0056 8481 ldd r24,Z+4
+ 604 0058 87FD sbrc r24,7
+ 605 005a 00C0 rjmp .L51
+ 606 .L36:
+ 607 005c AA81 ldd r26,Y+2
+ 608 005e BB81 ldd r27,Y+3
+ 609 0060 1A96 adiw r26,10
+ 610 0062 6D90 ld r6,X+
+ 611 0064 7D90 ld r7,X+
+ 612 0066 8D90 ld r8,X+
+ 613 0068 9C90 ld r9,X
+ 614 006a 1D97 sbiw r26,10+3
+ 615 006c 2E2D mov r18,r14
+ 616 006e 3D2D mov r19,r13
+ 617 0070 4C2D mov r20,r12
+ 618 0072 5B2D mov r21,r11
+ 619 0074 C901 movw r24,r18
+ 620 0076 DA01 movw r26,r20
+ 621 0078 5C01 movw r10,r24
+ 622 007a 6D01 movw r12,r26
+ 623 007c 6A14 cp r6,r10
+ 624 007e 7B04 cpc r7,r11
+ 625 0080 8C04 cpc r8,r12
+ 626 0082 9D04 cpc r9,r13
+ 627 0084 00F4 brsh .L37
+ 628 .LVL60:
+ 629 0086 6401 movw r12,r8
+ 630 0088 5301 movw r10,r6
+ 631 .LVL61:
+ 632 .L37:
+ 633 .LSM48:
+ 634 008a EA81 ldd r30,Y+2
+ 635 008c FB81 ldd r31,Y+3
+ 636 008e 2681 ldd r18,Z+6
+ 637 0090 3781 ldd r19,Z+7
+ 638 0092 4085 ldd r20,Z+8
+ 639 0094 5185 ldd r21,Z+9
+ 640 .LVL62:
+ 641 .LSM49:
+ 642 0096 1682 std Z+6,__zero_reg__
+ 643 0098 1782 std Z+7,__zero_reg__
+ 644 009a 1086 std Z+8,__zero_reg__
+ 645 009c 1186 std Z+9,__zero_reg__
+ 646 009e 8FEF ldi r24,lo8(-1)
+ 647 00a0 8583 std Z+5,r24
+ 648 .LSM50:
+ 649 00a2 A114 cp r10,__zero_reg__
+ 650 00a4 B104 cpc r11,__zero_reg__
+ 651 00a6 C104 cpc r12,__zero_reg__
+ 652 00a8 D104 cpc r13,__zero_reg__
+ 653 00aa 01F4 brne .+2
+ 654 00ac 00C0 rjmp .L38
+ 655 .LSM51:
+ 656 00ae 0190 ld __tmp_reg__,Z+
+ 657 00b0 F081 ld r31,Z
+ 658 00b2 E02D mov r30,__tmp_reg__
+ 659 00b4 8281 ldd r24,Z+2
+ 660 00b6 682E mov r6,r24
+ 661 .LVL63:
+ 662 00b8 7724 clr r7
+ 663 .LVL64:
+ 664 00ba 8824 clr r8
+ 665 00bc 9924 clr r9
+ 666 .LVL65:
+ 667 00be 09E0 ldi r16,9
+ 668 00c0 660C 1: lsl r6
+ 669 00c2 771C rol r7
+ 670 00c4 881C rol r8
+ 671 00c6 991C rol r9
+ 672 00c8 0A95 dec r16
+ 673 00ca 01F4 brne 1b
+ 674 .LVL66:
+ 675 .LSM52:
+ 676 00cc 2115 cp r18,__zero_reg__
+ 677 00ce 3105 cpc r19,__zero_reg__
+ 678 00d0 4105 cpc r20,__zero_reg__
+ 679 00d2 5105 cpc r21,__zero_reg__
+ 680 00d4 01F0 breq .L39
+ 681 00d6 1901 movw r2,r18
+ 682 00d8 2A01 movw r4,r20
+ 683 00da 0894 sec
+ 684 00dc 2108 sbc r2,__zero_reg__
+ 685 00de 3108 sbc r3,__zero_reg__
+ 686 00e0 4108 sbc r4,__zero_reg__
+ 687 00e2 5108 sbc r5,__zero_reg__
+ 688 00e4 C601 movw r24,r12
+ 689 00e6 B501 movw r22,r10
+ 690 00e8 6150 subi r22,lo8(-(-1))
+ 691 00ea 7040 sbci r23,hi8(-(-1))
+ 692 00ec 8040 sbci r24,hlo8(-(-1))
+ 693 00ee 9040 sbci r25,hhi8(-(-1))
+ 694 00f0 A401 movw r20,r8
+ 695 00f2 9301 movw r18,r6
+ 696 .LVL67:
+ 697 00f4 0E94 0000 call __udivmodsi4
+ 698 00f8 7901 movw r14,r18
+ 699 00fa 8A01 movw r16,r20
+ 700 00fc C201 movw r24,r4
+ 701 00fe B101 movw r22,r2
+ 702 0100 A401 movw r20,r8
+ 703 0102 9301 movw r18,r6
+ 704 0104 0E94 0000 call __udivmodsi4
+ 705 0108 E216 cp r14,r18
+ 706 010a F306 cpc r15,r19
+ 707 010c 0407 cpc r16,r20
+ 708 010e 1507 cpc r17,r21
+ 709 0110 00F0 brlo .L39
+ 710 .LSM53:
+ 711 0112 8827 clr r24
+ 712 0114 9927 clr r25
+ 713 0116 DC01 movw r26,r24
+ 714 0118 8619 sub r24,r6
+ 715 011a 9709 sbc r25,r7
+ 716 011c A809 sbc r26,r8
+ 717 011e B909 sbc r27,r9
+ 718 0120 8221 and r24,r2
+ 719 0122 9321 and r25,r3
+ 720 0124 A421 and r26,r4
+ 721 0126 B521 and r27,r5
+ 722 0128 EA81 ldd r30,Y+2
+ 723 012a FB81 ldd r31,Y+3
+ 724 012c 8683 std Z+6,r24
+ 725 012e 9783 std Z+7,r25
+ 726 0130 A087 std Z+8,r26
+ 727 0132 B187 std Z+9,r27
+ 728 .LSM54:
+ 729 0134 A81A sub r10,r24
+ 730 0136 B90A sbc r11,r25
+ 731 0138 CA0A sbc r12,r26
+ 732 013a DB0A sbc r13,r27
+ 733 .LSM55:
+ 734 013c 4289 ldd r20,Z+18
+ 735 013e 5389 ldd r21,Z+19
+ 736 0140 6489 ldd r22,Z+20
+ 737 0142 7589 ldd r23,Z+21
+ 738 .LVL68:
+ 739 0144 00C0 rjmp .L40
+ 740 .LVL69:
+ 741 .L39:
+ 742 .LSM56:
+ 743 0146 AA81 ldd r26,Y+2
+ 744 0148 BB81 ldd r27,Y+3
+ 745 014a 1E96 adiw r26,14
+ 746 014c 4D91 ld r20,X+
+ 747 014e 5D91 ld r21,X+
+ 748 0150 6D91 ld r22,X+
+ 749 0152 7C91 ld r23,X
+ 750 0154 5197 sbiw r26,14+3
+ 751 .LVL70:
+ 752 .LSM57:
+ 753 0156 FD01 movw r30,r26
+ 754 0158 428B std Z+18,r20
+ 755 015a 538B std Z+19,r21
+ 756 015c 648B std Z+20,r22
+ 757 015e 758B std Z+21,r23
+ 758 .L40:
+ 759 .LSM58:
+ 760 0160 4115 cp r20,__zero_reg__
+ 761 0162 5105 cpc r21,__zero_reg__
+ 762 0164 6105 cpc r22,__zero_reg__
+ 763 0166 7105 cpc r23,__zero_reg__
+ 764 0168 01F0 breq .+2
+ 765 016a 00C0 rjmp .L49
+ 766 016c 00C0 rjmp .L38
+ 767 .L45:
+ 768 .LSM59:
+ 769 016e AA81 ldd r26,Y+2
+ 770 0170 BB81 ldd r27,Y+3
+ 771 0172 8D91 ld r24,X+
+ 772 0174 9C91 ld r25,X
+ 773 0176 0E94 0000 call get_fat
+ 774 .LVL71:
+ 775 017a AB01 movw r20,r22
+ 776 017c BC01 movw r22,r24
+ 777 .LVL72:
+ 778 .LSM60:
+ 779 017e 4F3F cpi r20,lo8(-1)
+ 780 0180 BFEF ldi r27,hi8(-1)
+ 781 0182 5B07 cpc r21,r27
+ 782 0184 BFEF ldi r27,hlo8(-1)
+ 783 0186 6B07 cpc r22,r27
+ 784 0188 BFEF ldi r27,hhi8(-1)
+ 785 018a 7B07 cpc r23,r27
+ 786 018c 01F4 brne .L42
+ 787 018e EA81 ldd r30,Y+2
+ 788 0190 FB81 ldd r31,Y+3
+ 789 0192 8481 ldd r24,Z+4
+ 790 0194 8068 ori r24,lo8(-128)
+ 791 0196 8483 std Z+4,r24
+ 792 0198 F1E0 ldi r31,lo8(1)
+ 793 .L50:
+ 794 019a F983 std Y+1,r31
+ 795 .LVL73:
+ 796 019c 00C0 rjmp .L35
+ 797 .L42:
+ 798 .LSM61:
+ 799 019e 4230 cpi r20,lo8(2)
+ 800 01a0 5105 cpc r21,__zero_reg__
+ 801 01a2 6105 cpc r22,__zero_reg__
+ 802 01a4 7105 cpc r23,__zero_reg__
+ 803 01a6 00F0 brlo .L43
+ 804 01a8 AA81 ldd r26,Y+2
+ 805 01aa BB81 ldd r27,Y+3
+ 806 01ac ED91 ld r30,X+
+ 807 01ae FC91 ld r31,X
+ 808 01b0 8685 ldd r24,Z+14
+ 809 01b2 9785 ldd r25,Z+15
+ 810 01b4 A089 ldd r26,Z+16
+ 811 01b6 B189 ldd r27,Z+17
+ 812 01b8 4817 cp r20,r24
+ 813 01ba 5907 cpc r21,r25
+ 814 01bc 6A07 cpc r22,r26
+ 815 01be 7B07 cpc r23,r27
+ 816 01c0 00F0 brlo .L44
+ 817 .L43:
+ 818 01c2 EA81 ldd r30,Y+2
+ 819 01c4 FB81 ldd r31,Y+3
+ 820 01c6 8481 ldd r24,Z+4
+ 821 01c8 8068 ori r24,lo8(-128)
+ 822 01ca 8483 std Z+4,r24
+ 823 .LVL74:
+ 824 .L51:
+ 825 01cc F2E0 ldi r31,lo8(2)
+ 826 01ce 00C0 rjmp .L50
+ 827 .LVL75:
+ 828 .L44:
+ 829 .LSM62:
+ 830 01d0 AA81 ldd r26,Y+2
+ 831 01d2 BB81 ldd r27,Y+3
+ 832 01d4 5296 adiw r26,18
+ 833 01d6 4D93 st X+,r20
+ 834 01d8 5D93 st X+,r21
+ 835 01da 6D93 st X+,r22
+ 836 01dc 7C93 st X,r23
+ 837 01de 5597 sbiw r26,18+3
+ 838 .LSM63:
+ 839 01e0 FD01 movw r30,r26
+ 840 01e2 8681 ldd r24,Z+6
+ 841 01e4 9781 ldd r25,Z+7
+ 842 01e6 A085 ldd r26,Z+8
+ 843 01e8 B185 ldd r27,Z+9
+ 844 01ea 860D add r24,r6
+ 845 01ec 971D adc r25,r7
+ 846 01ee A81D adc r26,r8
+ 847 01f0 B91D adc r27,r9
+ 848 01f2 8683 std Z+6,r24
+ 849 01f4 9783 std Z+7,r25
+ 850 01f6 A087 std Z+8,r26
+ 851 01f8 B187 std Z+9,r27
+ 852 .LSM64:
+ 853 01fa A618 sub r10,r6
+ 854 01fc B708 sbc r11,r7
+ 855 01fe C808 sbc r12,r8
+ 856 0200 D908 sbc r13,r9
+ 857 .LVL76:
+ 858 .L49:
+ 859 .LSM65:
+ 860 0202 6A14 cp r6,r10
+ 861 0204 7B04 cpc r7,r11
+ 862 0206 8C04 cpc r8,r12
+ 863 0208 9D04 cpc r9,r13
+ 864 020a 00F4 brsh .+2
+ 865 020c 00C0 rjmp .L45
+ 866 .LVL77:
+ 867 .LSM66:
+ 868 020e EA81 ldd r30,Y+2
+ 869 0210 FB81 ldd r31,Y+3
+ 870 0212 8681 ldd r24,Z+6
+ 871 0214 9781 ldd r25,Z+7
+ 872 0216 A085 ldd r26,Z+8
+ 873 0218 B185 ldd r27,Z+9
+ 874 021a 8A0D add r24,r10
+ 875 021c 9B1D adc r25,r11
+ 876 021e AC1D adc r26,r12
+ 877 0220 BD1D adc r27,r13
+ 878 0222 8683 std Z+6,r24
+ 879 0224 9783 std Z+7,r25
+ 880 0226 A087 std Z+8,r26
+ 881 0228 B187 std Z+9,r27
+ 882 .LSM67:
+ 883 022a D601 movw r26,r12
+ 884 022c C501 movw r24,r10
+ 885 022e 19E0 ldi r17,9
+ 886 0230 B695 1: lsr r27
+ 887 0232 A795 ror r26
+ 888 0234 9795 ror r25
+ 889 0236 8795 ror r24
+ 890 0238 1A95 dec r17
+ 891 023a 01F4 brne 1b
+ 892 023c E82E mov r14,r24
+ 893 023e 8583 std Z+5,r24
+ 894 .LSM68:
+ 895 0240 8FEF ldi r24,lo8(511)
+ 896 0242 91E0 ldi r25,hi8(511)
+ 897 0244 A0E0 ldi r26,hlo8(511)
+ 898 0246 B0E0 ldi r27,hhi8(511)
+ 899 0248 A822 and r10,r24
+ 900 024a B922 and r11,r25
+ 901 024c CA22 and r12,r26
+ 902 024e DB22 and r13,r27
+ 903 0250 A114 cp r10,__zero_reg__
+ 904 0252 B104 cpc r11,__zero_reg__
+ 905 0254 C104 cpc r12,__zero_reg__
+ 906 0256 D104 cpc r13,__zero_reg__
+ 907 0258 01F0 breq .L38
+ 908 .LSM69:
+ 909 025a 8081 ld r24,Z
+ 910 025c 9181 ldd r25,Z+1
+ 911 025e 0E94 0000 call clust2sect
+ 912 .LVL78:
+ 913 .LSM70:
+ 914 0262 6115 cp r22,__zero_reg__
+ 915 0264 7105 cpc r23,__zero_reg__
+ 916 0266 8105 cpc r24,__zero_reg__
+ 917 0268 9105 cpc r25,__zero_reg__
+ 918 .LVL79:
+ 919 026a 01F4 brne .L46
+ 920 026c AA81 ldd r26,Y+2
+ 921 026e BB81 ldd r27,Y+3
+ 922 0270 1496 adiw r26,4
+ 923 0272 8C91 ld r24,X
+ 924 0274 1497 sbiw r26,4
+ 925 0276 8068 ori r24,lo8(-128)
+ 926 0278 1496 adiw r26,4
+ 927 027a 8C93 st X,r24
+ 928 027c B2E0 ldi r27,lo8(2)
+ 929 027e B983 std Y+1,r27
+ 930 .LVL80:
+ 931 0280 00C0 rjmp .L35
+ 932 .L46:
+ 933 .LSM71:
+ 934 0282 9B01 movw r18,r22
+ 935 0284 AC01 movw r20,r24
+ 936 0286 2E0D add r18,r14
+ 937 0288 311D adc r19,__zero_reg__
+ 938 028a 411D adc r20,__zero_reg__
+ 939 028c 511D adc r21,__zero_reg__
+ 940 .LVL81:
+ 941 .LSM72:
+ 942 028e E394 inc r14
+ 943 0290 EA81 ldd r30,Y+2
+ 944 0292 FB81 ldd r31,Y+3
+ 945 0294 E582 std Z+5,r14
+ 946 0296 00C0 rjmp .L47
+ 947 .LVL82:
+ 948 .L38:
+ 949 0298 20E0 ldi r18,lo8(0)
+ 950 029a 30E0 ldi r19,hi8(0)
+ 951 029c 40E0 ldi r20,hlo8(0)
+ 952 029e 50E0 ldi r21,hhi8(0)
+ 953 .LVL83:
+ 954 .L47:
+ 955 .LSM73:
+ 956 02a0 EA81 ldd r30,Y+2
+ 957 02a2 FB81 ldd r31,Y+3
+ 958 02a4 8681 ldd r24,Z+6
+ 959 02a6 9781 ldd r25,Z+7
+ 960 02a8 A085 ldd r26,Z+8
+ 961 02aa B185 ldd r27,Z+9
+ 962 02ac 9170 andi r25,hi8(511)
+ 963 02ae A070 andi r26,hlo8(511)
+ 964 02b0 B070 andi r27,hhi8(511)
+ 965 02b2 0097 sbiw r24,0
+ 966 02b4 A105 cpc r26,__zero_reg__
+ 967 02b6 B105 cpc r27,__zero_reg__
+ 968 02b8 01F0 breq .L35
+ 969 02ba 8689 ldd r24,Z+22
+ 970 02bc 9789 ldd r25,Z+23
+ 971 02be A08D ldd r26,Z+24
+ 972 02c0 B18D ldd r27,Z+25
+ 973 02c2 2817 cp r18,r24
+ 974 02c4 3907 cpc r19,r25
+ 975 02c6 4A07 cpc r20,r26
+ 976 02c8 5B07 cpc r21,r27
+ 977 02ca 01F0 breq .L35
+ 978 .LSM74:
+ 979 02cc 268B std Z+22,r18
+ 980 02ce 378B std Z+23,r19
+ 981 02d0 408F std Z+24,r20
+ 982 02d2 518F std Z+25,r21
+ 983 .LVL84:
+ 984 .L35:
+ 985 .LSM75:
+ 986 02d4 8981 ldd r24,Y+1
+ 987 /* epilogue start */
+ 988 02d6 0F90 pop __tmp_reg__
+ 989 02d8 0F90 pop __tmp_reg__
+ 990 02da 0F90 pop __tmp_reg__
+ 991 02dc CF91 pop r28
+ 992 02de DF91 pop r29
+ 993 02e0 1F91 pop r17
+ 994 02e2 0F91 pop r16
+ 995 02e4 FF90 pop r15
+ 996 02e6 EF90 pop r14
+ 997 02e8 DF90 pop r13
+ 998 .LVL85:
+ 999 02ea CF90 pop r12
+ 1000 .LVL86:
+ 1001 02ec BF90 pop r11
+ 1002 .LVL87:
+ 1003 02ee AF90 pop r10
+ 1004 .LVL88:
+ 1005 02f0 9F90 pop r9
+ 1006 02f2 8F90 pop r8
+ 1007 .LVL89:
+ 1008 02f4 7F90 pop r7
+ 1009 .LVL90:
+ 1010 02f6 6F90 pop r6
+ 1011 .LVL91:
+ 1012 02f8 5F90 pop r5
+ 1013 02fa 4F90 pop r4
+ 1014 02fc 3F90 pop r3
+ 1015 02fe 2F90 pop r2
+ 1016 0300 0895 ret
+ 1017 .LFE73:
+ 1019 .section .text.dir_seek,"ax",@progbits
+ 1021 dir_seek:
+ 1022 .LFB61:
+ 1023 .LSM76:
+ 1024 .LVL92:
+ 1025 0000 EF92 push r14
+ 1026 0002 FF92 push r15
+ 1027 0004 0F93 push r16
+ 1028 0006 1F93 push r17
+ 1029 0008 CF93 push r28
+ 1030 000a DF93 push r29
+ 1031 /* prologue: function */
+ 1032 /* frame size = 0 */
+ 1033 000c 8C01 movw r16,r24
+ 1034 000e EB01 movw r28,r22
+ 1035 .LSM77:
+ 1036 0010 DC01 movw r26,r24
+ 1037 0012 1596 adiw r26,4+1
+ 1038 0014 7C93 st X,r23
+ 1039 0016 6E93 st -X,r22
+ 1040 0018 1497 sbiw r26,4
+ 1041 .LSM78:
+ 1042 001a 1696 adiw r26,6
+ 1043 001c 4D91 ld r20,X+
+ 1044 001e 5D91 ld r21,X+
+ 1045 0020 6D91 ld r22,X+
+ 1046 0022 7C91 ld r23,X
+ 1047 0024 1997 sbiw r26,6+3
+ 1048 .LVL93:
+ 1049 .LSM79:
+ 1050 0026 4130 cpi r20,lo8(1)
+ 1051 0028 5105 cpc r21,__zero_reg__
+ 1052 002a 6105 cpc r22,__zero_reg__
+ 1053 002c 7105 cpc r23,__zero_reg__
+ 1054 002e 01F4 brne .+2
+ 1055 0030 00C0 rjmp .L53
+ 1056 0032 ED91 ld r30,X+
+ 1057 0034 FC91 ld r31,X
+ 1058 0036 8685 ldd r24,Z+14
+ 1059 0038 9785 ldd r25,Z+15
+ 1060 003a A089 ldd r26,Z+16
+ 1061 003c B189 ldd r27,Z+17
+ 1062 .LVL94:
+ 1063 003e 4817 cp r20,r24
+ 1064 0040 5907 cpc r21,r25
+ 1065 0042 6A07 cpc r22,r26
+ 1066 0044 7B07 cpc r23,r27
+ 1067 0046 00F0 brlo .+2
+ 1068 0048 00C0 rjmp .L53
+ 1069 .LSM80:
+ 1070 004a 4115 cp r20,__zero_reg__
+ 1071 004c 5105 cpc r21,__zero_reg__
+ 1072 004e 6105 cpc r22,__zero_reg__
+ 1073 0050 7105 cpc r23,__zero_reg__
+ 1074 0052 01F4 brne .L54
+ 1075 0054 8081 ld r24,Z
+ 1076 0056 8330 cpi r24,lo8(3)
+ 1077 0058 01F4 brne .L55
+ 1078 .LSM81:
+ 1079 005a 4689 ldd r20,Z+22
+ 1080 005c 5789 ldd r21,Z+23
+ 1081 005e 608D ldd r22,Z+24
+ 1082 0060 718D ldd r23,Z+25
+ 1083 .LSM82:
+ 1084 0062 4115 cp r20,__zero_reg__
+ 1085 0064 5105 cpc r21,__zero_reg__
+ 1086 0066 6105 cpc r22,__zero_reg__
+ 1087 0068 7105 cpc r23,__zero_reg__
+ 1088 006a 01F4 brne .L54
+ 1089 .L55:
+ 1090 .LSM83:
+ 1091 006c F801 movw r30,r16
+ 1092 006e 1286 std Z+10,__zero_reg__
+ 1093 0070 1386 std Z+11,__zero_reg__
+ 1094 0072 1486 std Z+12,__zero_reg__
+ 1095 0074 1586 std Z+13,__zero_reg__
+ 1096 .LSM84:
+ 1097 0076 0190 ld __tmp_reg__,Z+
+ 1098 0078 F081 ld r31,Z
+ 1099 007a E02D mov r30,__tmp_reg__
+ 1100 007c 8085 ldd r24,Z+8
+ 1101 007e 9185 ldd r25,Z+9
+ 1102 0080 C817 cp r28,r24
+ 1103 0082 D907 cpc r29,r25
+ 1104 0084 00F0 brlo .+2
+ 1105 0086 00C0 rjmp .L53
+ 1106 .LVL95:
+ 1107 .LSM85:
+ 1108 0088 CE01 movw r24,r28
+ 1109 008a A4E0 ldi r26,4
+ 1110 008c 9695 1: lsr r25
+ 1111 008e 8795 ror r24
+ 1112 0090 AA95 dec r26
+ 1113 0092 01F4 brne 1b
+ 1114 0094 A0E0 ldi r26,lo8(0)
+ 1115 0096 B0E0 ldi r27,hi8(0)
+ 1116 0098 2689 ldd r18,Z+22
+ 1117 009a 3789 ldd r19,Z+23
+ 1118 009c 408D ldd r20,Z+24
+ 1119 009e 518D ldd r21,Z+25
+ 1120 00a0 820F add r24,r18
+ 1121 00a2 931F adc r25,r19
+ 1122 00a4 A41F adc r26,r20
+ 1123 00a6 B51F adc r27,r21
+ 1124 00a8 F801 movw r30,r16
+ 1125 00aa 8687 std Z+14,r24
+ 1126 00ac 9787 std Z+15,r25
+ 1127 00ae A08B std Z+16,r26
+ 1128 00b0 B18B std Z+17,r27
+ 1129 00b2 00C0 rjmp .L56
+ 1130 .LVL96:
+ 1131 .L54:
+ 1132 .LSM86:
+ 1133 00b4 8281 ldd r24,Z+2
+ 1134 00b6 E82E mov r14,r24
+ 1135 .LVL97:
+ 1136 00b8 FF24 clr r15
+ 1137 .LVL98:
+ 1138 00ba E4E0 ldi r30,4
+ 1139 00bc EE0C 1: lsl r14
+ 1140 00be FF1C rol r15
+ 1141 00c0 EA95 dec r30
+ 1142 00c2 01F4 brne 1b
+ 1143 .LVL99:
+ 1144 00c4 00C0 rjmp .L57
+ 1145 .LVL100:
+ 1146 .L60:
+ 1147 .LSM87:
+ 1148 00c6 0E94 0000 call get_fat
+ 1149 .LVL101:
+ 1150 00ca AB01 movw r20,r22
+ 1151 00cc BC01 movw r22,r24
+ 1152 .LVL102:
+ 1153 .LSM88:
+ 1154 00ce 4F3F cpi r20,lo8(-1)
+ 1155 00d0 FFEF ldi r31,hi8(-1)
+ 1156 00d2 5F07 cpc r21,r31
+ 1157 00d4 FFEF ldi r31,hlo8(-1)
+ 1158 00d6 6F07 cpc r22,r31
+ 1159 00d8 FFEF ldi r31,hhi8(-1)
+ 1160 00da 7F07 cpc r23,r31
+ 1161 00dc 01F4 brne .L58
+ 1162 00de 81E0 ldi r24,lo8(1)
+ 1163 00e0 00C0 rjmp .L59
+ 1164 .L58:
+ 1165 .LSM89:
+ 1166 00e2 4230 cpi r20,lo8(2)
+ 1167 00e4 5105 cpc r21,__zero_reg__
+ 1168 00e6 6105 cpc r22,__zero_reg__
+ 1169 00e8 7105 cpc r23,__zero_reg__
+ 1170 00ea 00F4 brsh .+2
+ 1171 00ec 00C0 rjmp .L53
+ 1172 00ee D801 movw r26,r16
+ 1173 00f0 ED91 ld r30,X+
+ 1174 00f2 FC91 ld r31,X
+ 1175 00f4 8685 ldd r24,Z+14
+ 1176 00f6 9785 ldd r25,Z+15
+ 1177 00f8 A089 ldd r26,Z+16
+ 1178 00fa B189 ldd r27,Z+17
+ 1179 00fc 4817 cp r20,r24
+ 1180 00fe 5907 cpc r21,r25
+ 1181 0100 6A07 cpc r22,r26
+ 1182 0102 7B07 cpc r23,r27
+ 1183 0104 00F4 brsh .L53
+ 1184 .LSM90:
+ 1185 0106 CE19 sub r28,r14
+ 1186 0108 DF09 sbc r29,r15
+ 1187 .LVL103:
+ 1188 .L57:
+ 1189 010a F801 movw r30,r16
+ 1190 010c 8081 ld r24,Z
+ 1191 010e 9181 ldd r25,Z+1
+ 1192 .LSM91:
+ 1193 0110 CE15 cp r28,r14
+ 1194 0112 DF05 cpc r29,r15
+ 1195 0114 00F4 brsh .L60
+ 1196 .LSM92:
+ 1197 0116 D801 movw r26,r16
+ 1198 0118 1A96 adiw r26,10
+ 1199 011a 4D93 st X+,r20
+ 1200 011c 5D93 st X+,r21
+ 1201 011e 6D93 st X+,r22
+ 1202 0120 7C93 st X,r23
+ 1203 0122 1D97 sbiw r26,10+3
+ 1204 .LSM93:
+ 1205 0124 0E94 0000 call clust2sect
+ 1206 .LVL104:
+ 1207 0128 9E01 movw r18,r28
+ 1208 012a 44E0 ldi r20,4
+ 1209 012c 3695 1: lsr r19
+ 1210 012e 2795 ror r18
+ 1211 0130 4A95 dec r20
+ 1212 0132 01F4 brne 1b
+ 1213 0134 40E0 ldi r20,lo8(0)
+ 1214 0136 50E0 ldi r21,hi8(0)
+ 1215 0138 260F add r18,r22
+ 1216 013a 371F adc r19,r23
+ 1217 013c 481F adc r20,r24
+ 1218 013e 591F adc r21,r25
+ 1219 0140 F801 movw r30,r16
+ 1220 0142 2687 std Z+14,r18
+ 1221 0144 3787 std Z+15,r19
+ 1222 0146 408B std Z+16,r20
+ 1223 0148 518B std Z+17,r21
+ 1224 .LVL105:
+ 1225 .L56:
+ 1226 .LSM94:
+ 1227 014a CF70 andi r28,lo8(15)
+ 1228 014c D070 andi r29,hi8(15)
+ 1229 014e 85E0 ldi r24,5
+ 1230 0150 CC0F 1: lsl r28
+ 1231 0152 DD1F rol r29
+ 1232 0154 8A95 dec r24
+ 1233 0156 01F4 brne 1b
+ 1234 0158 A296 adiw r28,34
+ 1235 015a D801 movw r26,r16
+ 1236 015c 8D91 ld r24,X+
+ 1237 015e 9C91 ld r25,X
+ 1238 0160 1197 sbiw r26,1
+ 1239 0162 8C0F add r24,r28
+ 1240 0164 9D1F adc r25,r29
+ 1241 0166 5396 adiw r26,18+1
+ 1242 0168 9C93 st X,r25
+ 1243 016a 8E93 st -X,r24
+ 1244 016c 5297 sbiw r26,18
+ 1245 016e 80E0 ldi r24,lo8(0)
+ 1246 0170 00C0 rjmp .L59
+ 1247 .LVL106:
+ 1248 .L53:
+ 1249 .LSM95:
+ 1250 0172 82E0 ldi r24,lo8(2)
+ 1251 .L59:
+ 1252 /* epilogue start */
+ 1253 .LSM96:
+ 1254 0174 DF91 pop r29
+ 1255 0176 CF91 pop r28
+ 1256 .LVL107:
+ 1257 0178 1F91 pop r17
+ 1258 017a 0F91 pop r16
+ 1259 .LVL108:
+ 1260 017c FF90 pop r15
+ 1261 .LVL109:
+ 1262 017e EF90 pop r14
+ 1263 .LVL110:
+ 1264 0180 0895 ret
+ 1265 .LFE61:
+ 1267 .section .text.f_read,"ax",@progbits
+ 1268 .global f_read
+ 1270 f_read:
+ 1271 .LFB71:
+ 1272 .LSM97:
+ 1273 .LVL111:
+ 1274 0000 2F92 push r2
+ 1275 0002 3F92 push r3
+ 1276 0004 4F92 push r4
+ 1277 0006 5F92 push r5
+ 1278 0008 7F92 push r7
+ 1279 000a 8F92 push r8
+ 1280 000c 9F92 push r9
+ 1281 000e AF92 push r10
+ 1282 0010 BF92 push r11
+ 1283 0012 CF92 push r12
+ 1284 0014 DF92 push r13
+ 1285 0016 EF92 push r14
+ 1286 0018 FF92 push r15
+ 1287 001a 0F93 push r16
+ 1288 001c 1F93 push r17
+ 1289 001e CF93 push r28
+ 1290 0020 DF93 push r29
+ 1291 /* prologue: function */
+ 1292 /* frame size = 0 */
+ 1293 0022 EC01 movw r28,r24
+ 1294 0024 162F mov r17,r22
+ 1295 0026 072F mov r16,r23
+ 1296 .LVL112:
+ 1297 0028 4A01 movw r8,r20
+ 1298 002a 1901 movw r2,r18
+ 1299 .LSM98:
+ 1300 002c D901 movw r26,r18
+ 1301 002e 1D92 st X+,__zero_reg__
+ 1302 0030 1C92 st X,__zero_reg__
+ 1303 .LSM99:
+ 1304 0032 6A81 ldd r22,Y+2
+ 1305 0034 7B81 ldd r23,Y+3
+ 1306 .LVL113:
+ 1307 0036 8881 ld r24,Y
+ 1308 0038 9981 ldd r25,Y+1
+ 1309 .LVL114:
+ 1310 003a 0E94 0000 call validate
+ 1311 .LVL115:
+ 1312 003e 782E mov r7,r24
+ 1313 .LVL116:
+ 1314 .LSM100:
+ 1315 0040 8823 tst r24
+ 1316 0042 01F0 breq .+2
+ 1317 0044 00C0 rjmp .L63
+ 1318 .LVL117:
+ 1319 .LSM101:
+ 1320 0046 8C81 ldd r24,Y+4
+ 1321 .LVL118:
+ 1322 0048 87FD sbrc r24,7
+ 1323 004a 00C0 rjmp .L85
+ 1324 .L64:
+ 1325 .LSM102:
+ 1326 004c 80FD sbrc r24,0
+ 1327 004e 00C0 rjmp .L65
+ 1328 0050 27E0 ldi r18,lo8(7)
+ 1329 0052 722E mov r7,r18
+ 1330 0054 00C0 rjmp .L63
+ 1331 .L65:
+ 1332 .LSM103:
+ 1333 0056 2A85 ldd r18,Y+10
+ 1334 0058 3B85 ldd r19,Y+11
+ 1335 005a 4C85 ldd r20,Y+12
+ 1336 005c 5D85 ldd r21,Y+13
+ 1337 .LVL119:
+ 1338 005e 8E81 ldd r24,Y+6
+ 1339 0060 9F81 ldd r25,Y+7
+ 1340 0062 A885 ldd r26,Y+8
+ 1341 0064 B985 ldd r27,Y+9
+ 1342 0066 281B sub r18,r24
+ 1343 0068 390B sbc r19,r25
+ 1344 006a 4A0B sbc r20,r26
+ 1345 006c 5B0B sbc r21,r27
+ 1346 .LSM104:
+ 1347 006e C401 movw r24,r8
+ 1348 0070 A0E0 ldi r26,lo8(0)
+ 1349 0072 B0E0 ldi r27,hi8(0)
+ 1350 .LVL120:
+ 1351 0074 2817 cp r18,r24
+ 1352 0076 3907 cpc r19,r25
+ 1353 0078 4A07 cpc r20,r26
+ 1354 007a 5B07 cpc r21,r27
+ 1355 007c 00F4 brsh .L66
+ 1356 .LVL121:
+ 1357 007e 4901 movw r8,r18
+ 1358 .LVL122:
+ 1359 .L66:
+ 1360 .LSM105:
+ 1361 0080 812F mov r24,r17
+ 1362 .LVL123:
+ 1363 0082 902F mov r25,r16
+ 1364 .LVL124:
+ 1365 0084 9C01 movw r18,r24
+ 1366 .LVL125:
+ 1367 0086 2901 movw r4,r18
+ 1368 .LVL126:
+ 1369 0088 00C0 rjmp .L67
+ 1370 .LVL127:
+ 1371 .L83:
+ 1372 .LSM106:
+ 1373 008a 2E81 ldd r18,Y+6
+ 1374 008c 3F81 ldd r19,Y+7
+ 1375 008e 4885 ldd r20,Y+8
+ 1376 0090 5985 ldd r21,Y+9
+ 1377 0092 DA01 movw r26,r20
+ 1378 0094 C901 movw r24,r18
+ 1379 0096 9170 andi r25,hi8(511)
+ 1380 0098 A070 andi r26,hlo8(511)
+ 1381 009a B070 andi r27,hhi8(511)
+ 1382 009c 0097 sbiw r24,0
+ 1383 009e A105 cpc r26,__zero_reg__
+ 1384 00a0 B105 cpc r27,__zero_reg__
+ 1385 00a2 01F0 breq .+2
+ 1386 00a4 00C0 rjmp .L68
+ 1387 .LSM107:
+ 1388 00a6 E881 ld r30,Y
+ 1389 00a8 F981 ldd r31,Y+1
+ 1390 .LVL128:
+ 1391 00aa 9D81 ldd r25,Y+5
+ 1392 .LVL129:
+ 1393 00ac 8281 ldd r24,Z+2
+ 1394 00ae 9817 cp r25,r24
+ 1395 00b0 00F0 brlo .L69
+ 1396 .LSM108:
+ 1397 00b2 2115 cp r18,__zero_reg__
+ 1398 00b4 3105 cpc r19,__zero_reg__
+ 1399 00b6 4105 cpc r20,__zero_reg__
+ 1400 00b8 5105 cpc r21,__zero_reg__
+ 1401 00ba 01F4 brne .L70
+ 1402 00bc 6E85 ldd r22,Y+14
+ 1403 00be 7F85 ldd r23,Y+15
+ 1404 00c0 8889 ldd r24,Y+16
+ 1405 00c2 9989 ldd r25,Y+17
+ 1406 .LVL130:
+ 1407 00c4 00C0 rjmp .L71
+ 1408 .LVL131:
+ 1409 .L70:
+ 1410 00c6 4A89 ldd r20,Y+18
+ 1411 00c8 5B89 ldd r21,Y+19
+ 1412 00ca 6C89 ldd r22,Y+20
+ 1413 00cc 7D89 ldd r23,Y+21
+ 1414 00ce CF01 movw r24,r30
+ 1415 00d0 0E94 0000 call get_fat
+ 1416 .LVL132:
+ 1417 .L71:
+ 1418 .LSM109:
+ 1419 00d4 6230 cpi r22,lo8(2)
+ 1420 00d6 7105 cpc r23,__zero_reg__
+ 1421 00d8 8105 cpc r24,__zero_reg__
+ 1422 00da 9105 cpc r25,__zero_reg__
+ 1423 00dc 00F4 brsh .L72
+ 1424 .LVL133:
+ 1425 .L87:
+ 1426 00de 8C81 ldd r24,Y+4
+ 1427 00e0 8068 ori r24,lo8(-128)
+ 1428 00e2 8C83 std Y+4,r24
+ 1429 .L85:
+ 1430 00e4 92E0 ldi r25,lo8(2)
+ 1431 00e6 792E mov r7,r25
+ 1432 00e8 00C0 rjmp .L63
+ 1433 .LVL134:
+ 1434 .L72:
+ 1435 .LSM110:
+ 1436 00ea 6F3F cpi r22,lo8(-1)
+ 1437 00ec BFEF ldi r27,hi8(-1)
+ 1438 00ee 7B07 cpc r23,r27
+ 1439 00f0 BFEF ldi r27,hlo8(-1)
+ 1440 00f2 8B07 cpc r24,r27
+ 1441 00f4 BFEF ldi r27,hhi8(-1)
+ 1442 00f6 9B07 cpc r25,r27
+ 1443 00f8 01F4 brne .+2
+ 1444 00fa 00C0 rjmp .L86
+ 1445 .L73:
+ 1446 .LSM111:
+ 1447 00fc 6A8B std Y+18,r22
+ 1448 00fe 7B8B std Y+19,r23
+ 1449 0100 8C8B std Y+20,r24
+ 1450 0102 9D8B std Y+21,r25
+ 1451 .LSM112:
+ 1452 0104 1D82 std Y+5,__zero_reg__
+ 1453 .LVL135:
+ 1454 .L69:
+ 1455 .LSM113:
+ 1456 0106 0881 ld r16,Y
+ 1457 0108 1981 ldd r17,Y+1
+ 1458 .LVL136:
+ 1459 010a 4A89 ldd r20,Y+18
+ 1460 010c 5B89 ldd r21,Y+19
+ 1461 010e 6C89 ldd r22,Y+20
+ 1462 0110 7D89 ldd r23,Y+21
+ 1463 0112 C801 movw r24,r16
+ 1464 0114 0E94 0000 call clust2sect
+ 1465 .LVL137:
+ 1466 .LSM114:
+ 1467 0118 6115 cp r22,__zero_reg__
+ 1468 011a 7105 cpc r23,__zero_reg__
+ 1469 011c 8105 cpc r24,__zero_reg__
+ 1470 011e 9105 cpc r25,__zero_reg__
+ 1471 0120 01F0 breq .L87
+ 1472 .LVL138:
+ 1473 .L74:
+ 1474 .LSM115:
+ 1475 0122 ED81 ldd r30,Y+5
+ 1476 0124 5B01 movw r10,r22
+ 1477 0126 6C01 movw r12,r24
+ 1478 0128 AE0E add r10,r30
+ 1479 012a B11C adc r11,__zero_reg__
+ 1480 012c C11C adc r12,__zero_reg__
+ 1481 012e D11C adc r13,__zero_reg__
+ 1482 .LVL139:
+ 1483 .LSM116:
+ 1484 0130 7401 movw r14,r8
+ 1485 0132 EF2C mov r14,r15
+ 1486 0134 FF24 clr r15
+ 1487 0136 E694 lsr r14
+ 1488 .LSM117:
+ 1489 0138 E114 cp r14,__zero_reg__
+ 1490 013a F104 cpc r15,__zero_reg__
+ 1491 013c 01F0 breq .L75
+ 1492 .LSM118:
+ 1493 013e D801 movw r26,r16
+ 1494 0140 1296 adiw r26,2
+ 1495 0142 2C91 ld r18,X
+ 1496 0144 F0E0 ldi r31,lo8(0)
+ 1497 0146 C701 movw r24,r14
+ 1498 0148 8E0F add r24,r30
+ 1499 014a 9F1F adc r25,r31
+ 1500 014c 622F mov r22,r18
+ 1501 014e 70E0 ldi r23,lo8(0)
+ 1502 0150 6817 cp r22,r24
+ 1503 0152 7907 cpc r23,r25
+ 1504 0154 00F4 brsh .L76
+ 1505 .LSM119:
+ 1506 0156 7B01 movw r14,r22
+ 1507 0158 EE1A sub r14,r30
+ 1508 015a FF0A sbc r15,r31
+ 1509 .L76:
+ 1510 .LSM120:
+ 1511 015c F801 movw r30,r16
+ 1512 015e 8181 ldd r24,Z+1
+ 1513 0160 B201 movw r22,r4
+ 1514 0162 A601 movw r20,r12
+ 1515 0164 9501 movw r18,r10
+ 1516 0166 0E2D mov r16,r14
+ 1517 0168 0E94 0000 call disk_read
+ 1518 016c 8823 tst r24
+ 1519 016e 01F4 brne .L86
+ 1520 .L77:
+ 1521 .LSM121:
+ 1522 0170 8D81 ldd r24,Y+5
+ 1523 0172 8E0D add r24,r14
+ 1524 0174 8D83 std Y+5,r24
+ 1525 .LSM122:
+ 1526 0176 B701 movw r22,r14
+ 1527 .LVL140:
+ 1528 0178 762F mov r23,r22
+ 1529 017a 6627 clr r22
+ 1530 017c 770F lsl r23
+ 1531 017e 00C0 rjmp .L78
+ 1532 .LVL141:
+ 1533 .L75:
+ 1534 .LSM123:
+ 1535 0180 AE8A std Y+22,r10
+ 1536 0182 BF8A std Y+23,r11
+ 1537 0184 C88E std Y+24,r12
+ 1538 0186 D98E std Y+25,r13
+ 1539 .LSM124:
+ 1540 0188 EF5F subi r30,lo8(-(1))
+ 1541 018a ED83 std Y+5,r30
+ 1542 .LVL142:
+ 1543 .L68:
+ 1544 .LSM125:
+ 1545 018c EE80 ldd r14,Y+6
+ 1546 018e FF80 ldd r15,Y+7
+ 1547 0190 0885 ldd r16,Y+8
+ 1548 0192 1985 ldd r17,Y+9
+ 1549 .LVL143:
+ 1550 .LSM126:
+ 1551 0194 4E89 ldd r20,Y+22
+ 1552 0196 5F89 ldd r21,Y+23
+ 1553 0198 688D ldd r22,Y+24
+ 1554 019a 798D ldd r23,Y+25
+ 1555 019c 8881 ld r24,Y
+ 1556 019e 9981 ldd r25,Y+1
+ 1557 01a0 0E94 0000 call move_window
+ 1558 .LVL144:
+ 1559 01a4 8823 tst r24
+ 1560 01a6 01F0 breq .L79
+ 1561 .LVL145:
+ 1562 .L86:
+ 1563 .LSM127:
+ 1564 01a8 8C81 ldd r24,Y+4
+ 1565 01aa 8068 ori r24,lo8(-128)
+ 1566 01ac 8C83 std Y+4,r24
+ 1567 01ae 7724 clr r7
+ 1568 01b0 7394 inc r7
+ 1569 01b2 00C0 rjmp .L63
+ 1570 .LVL146:
+ 1571 .L79:
+ 1572 .LSM128:
+ 1573 01b4 C701 movw r24,r14
+ 1574 01b6 9170 andi r25,hi8(511)
+ 1575 01b8 20E0 ldi r18,lo8(512)
+ 1576 01ba 32E0 ldi r19,hi8(512)
+ 1577 01bc 281B sub r18,r24
+ 1578 01be 390B sbc r19,r25
+ 1579 01c0 B401 movw r22,r8
+ 1580 .LVL147:
+ 1581 01c2 2815 cp r18,r8
+ 1582 01c4 3905 cpc r19,r9
+ 1583 01c6 00F4 brsh .L80
+ 1584 .LVL148:
+ 1585 01c8 B901 movw r22,r18
+ 1586 .L80:
+ 1587 .LSM129:
+ 1588 01ca 9B01 movw r18,r22
+ 1589 .LVL149:
+ 1590 .LBB4:
+ 1591 .LBB5:
+ 1592 .LSM130:
+ 1593 01cc 8E81 ldd r24,Y+6
+ 1594 01ce 9F81 ldd r25,Y+7
+ 1595 01d0 9170 andi r25,hi8(511)
+ 1596 01d2 8296 adiw r24,34
+ 1597 01d4 E881 ld r30,Y
+ 1598 01d6 F981 ldd r31,Y+1
+ 1599 .LVL150:
+ 1600 01d8 E80F add r30,r24
+ 1601 01da F91F adc r31,r25
+ 1602 01dc D201 movw r26,r4
+ 1603 01de 00C0 rjmp .L81
+ 1604 .LVL151:
+ 1605 .L82:
+ 1606 .LSM131:
+ 1607 01e0 8191 ld r24,Z+
+ 1608 01e2 8D93 st X+,r24
+ 1609 .L81:
+ 1610 01e4 2150 subi r18,lo8(-(-1))
+ 1611 01e6 3040 sbci r19,hi8(-(-1))
+ 1612 01e8 8FEF ldi r24,hi8(-1)
+ 1613 01ea 2F3F cpi r18,lo8(-1)
+ 1614 01ec 3807 cpc r19,r24
+ 1615 01ee 01F4 brne .L82
+ 1616 .LVL152:
+ 1617 .L78:
+ 1618 .LBE5:
+ 1619 .LBE4:
+ 1620 .LSM132:
+ 1621 01f0 460E add r4,r22
+ 1622 01f2 571E adc r5,r23
+ 1623 01f4 CB01 movw r24,r22
+ 1624 01f6 A0E0 ldi r26,lo8(0)
+ 1625 01f8 B0E0 ldi r27,hi8(0)
+ 1626 .LVL153:
+ 1627 01fa 2E81 ldd r18,Y+6
+ 1628 01fc 3F81 ldd r19,Y+7
+ 1629 01fe 4885 ldd r20,Y+8
+ 1630 0200 5985 ldd r21,Y+9
+ 1631 .LVL154:
+ 1632 0202 280F add r18,r24
+ 1633 0204 391F adc r19,r25
+ 1634 0206 4A1F adc r20,r26
+ 1635 0208 5B1F adc r21,r27
+ 1636 020a 2E83 std Y+6,r18
+ 1637 020c 3F83 std Y+7,r19
+ 1638 020e 4887 std Y+8,r20
+ 1639 0210 5987 std Y+9,r21
+ 1640 0212 D101 movw r26,r2
+ 1641 .LVL155:
+ 1642 0214 8D91 ld r24,X+
+ 1643 0216 9C91 ld r25,X
+ 1644 0218 1197 sbiw r26,1
+ 1645 021a 860F add r24,r22
+ 1646 021c 971F adc r25,r23
+ 1647 021e 8D93 st X+,r24
+ 1648 0220 9C93 st X,r25
+ 1649 0222 861A sub r8,r22
+ 1650 0224 970A sbc r9,r23
+ 1651 .LVL156:
+ 1652 .L67:
+ 1653 .LSM133:
+ 1654 0226 8114 cp r8,__zero_reg__
+ 1655 0228 9104 cpc r9,__zero_reg__
+ 1656 022a 01F0 breq .+2
+ 1657 022c 00C0 rjmp .L83
+ 1658 .LVL157:
+ 1659 .L63:
+ 1660 .LSM134:
+ 1661 022e 872D mov r24,r7
+ 1662 /* epilogue start */
+ 1663 0230 DF91 pop r29
+ 1664 0232 CF91 pop r28
+ 1665 .LVL158:
+ 1666 0234 1F91 pop r17
+ 1667 .LVL159:
+ 1668 0236 0F91 pop r16
+ 1669 .LVL160:
+ 1670 0238 FF90 pop r15
+ 1671 023a EF90 pop r14
+ 1672 .LVL161:
+ 1673 023c DF90 pop r13
+ 1674 023e CF90 pop r12
+ 1675 0240 BF90 pop r11
+ 1676 0242 AF90 pop r10
+ 1677 .LVL162:
+ 1678 0244 9F90 pop r9
+ 1679 0246 8F90 pop r8
+ 1680 .LVL163:
+ 1681 0248 7F90 pop r7
+ 1682 .LVL164:
+ 1683 024a 5F90 pop r5
+ 1684 024c 4F90 pop r4
+ 1685 .LVL165:
+ 1686 024e 3F90 pop r3
+ 1687 0250 2F90 pop r2
+ 1688 .LVL166:
+ 1689 0252 0895 ret
+ 1690 .LFE71:
+ 1692 .section .text.check_fs,"ax",@progbits
+ 1694 check_fs:
+ 1695 .LFB66:
+ 1696 .LSM135:
+ 1697 .LVL167:
+ 1698 0000 0F93 push r16
+ 1699 0002 CF93 push r28
+ 1700 0004 DF93 push r29
+ 1701 /* prologue: function */
+ 1702 /* frame size = 0 */
+ 1703 0006 EC01 movw r28,r24
+ 1704 0008 9A01 movw r18,r20
+ 1705 000a AB01 movw r20,r22
+ 1706 .LSM136:
+ 1707 000c BC01 movw r22,r24
+ 1708 000e 6E5D subi r22,lo8(-(34))
+ 1709 0010 7F4F sbci r23,hi8(-(34))
+ 1710 0012 8981 ldd r24,Y+1
+ 1711 .LVL168:
+ 1712 0014 01E0 ldi r16,lo8(1)
+ 1713 0016 0E94 0000 call disk_read
+ 1714 .LVL169:
+ 1715 001a 8823 tst r24
+ 1716 001c 01F0 breq .L89
+ 1717 001e 23E0 ldi r18,lo8(3)
+ 1718 0020 00C0 rjmp .L90
+ 1719 .L89:
+ 1720 .LSM137:
+ 1721 0022 C05E subi r28,lo8(-(544))
+ 1722 0024 DD4F sbci r29,hi8(-(544))
+ 1723 0026 8881 ld r24,Y
+ 1724 0028 9981 ldd r25,Y+1
+ 1725 002a C052 subi r28,lo8(-(-544))
+ 1726 002c D240 sbci r29,hi8(-(-544))
+ 1727 002e 8555 subi r24,lo8(-21931)
+ 1728 0030 9A4A sbci r25,hi8(-21931)
+ 1729 0032 01F0 breq .L91
+ 1730 0034 22E0 ldi r18,lo8(2)
+ 1731 0036 00C0 rjmp .L90
+ 1732 .L91:
+ 1733 .LSM138:
+ 1734 0038 C85A subi r28,lo8(-(88))
+ 1735 003a DF4F sbci r29,hi8(-(88))
+ 1736 003c 8881 ld r24,Y
+ 1737 003e 9981 ldd r25,Y+1
+ 1738 0040 AA81 ldd r26,Y+2
+ 1739 0042 BB81 ldd r27,Y+3
+ 1740 0044 C855 subi r28,lo8(-(-88))
+ 1741 0046 D040 sbci r29,hi8(-(-88))
+ 1742 0048 B070 andi r27,hhi8(16777215)
+ 1743 004a 8654 subi r24,lo8(5521734)
+ 1744 004c 9144 sbci r25,hi8(5521734)
+ 1745 004e A445 sbci r26,hlo8(5521734)
+ 1746 0050 B040 sbci r27,hhi8(5521734)
+ 1747 0052 01F4 brne .L92
+ 1748 0054 20E0 ldi r18,lo8(0)
+ 1749 0056 00C0 rjmp .L90
+ 1750 .L92:
+ 1751 0058 20E0 ldi r18,lo8(0)
+ 1752 005a CC58 subi r28,lo8(-(116))
+ 1753 005c DF4F sbci r29,hi8(-(116))
+ 1754 005e 8881 ld r24,Y
+ 1755 0060 9981 ldd r25,Y+1
+ 1756 0062 AA81 ldd r26,Y+2
+ 1757 0064 BB81 ldd r27,Y+3
+ 1758 0066 B070 andi r27,hhi8(16777215)
+ 1759 0068 8654 subi r24,lo8(5521734)
+ 1760 006a 9144 sbci r25,hi8(5521734)
+ 1761 006c A445 sbci r26,hlo8(5521734)
+ 1762 006e B040 sbci r27,hhi8(5521734)
+ 1763 0070 01F0 breq .L90
+ 1764 0072 21E0 ldi r18,lo8(1)
+ 1765 .L90:
+ 1766 .LSM139:
+ 1767 0074 822F mov r24,r18
+ 1768 /* epilogue start */
+ 1769 0076 DF91 pop r29
+ 1770 0078 CF91 pop r28
+ 1771 .LVL170:
+ 1772 007a 0F91 pop r16
+ 1773 007c 0895 ret
+ 1774 .LFE66:
+ 1776 .section .text.chk_mounted,"ax",@progbits
+ 1777 .global chk_mounted
+ 1779 chk_mounted:
+ 1780 .LFB67:
+ 1781 .LSM140:
+ 1782 .LVL171:
+ 1783 0000 AF92 push r10
+ 1784 0002 BF92 push r11
+ 1785 0004 CF92 push r12
+ 1786 0006 DF92 push r13
+ 1787 0008 EF92 push r14
+ 1788 000a FF92 push r15
+ 1789 000c 0F93 push r16
+ 1790 000e 1F93 push r17
+ 1791 0010 CF93 push r28
+ 1792 0012 DF93 push r29
+ 1793 /* prologue: function */
+ 1794 /* frame size = 0 */
+ 1795 0014 DC01 movw r26,r24
+ 1796 0016 AB01 movw r20,r22
+ 1797 .LVL172:
+ 1798 .LSM141:
+ 1799 0018 ED91 ld r30,X+
+ 1800 001a FC91 ld r31,X
+ 1801 001c 1197 sbiw r26,1
+ 1802 .LVL173:
+ 1803 .LSM142:
+ 1804 001e 8081 ld r24,Z
+ 1805 .LVL174:
+ 1806 0020 282F mov r18,r24
+ 1807 .LVL175:
+ 1808 0022 30E0 ldi r19,lo8(0)
+ 1809 .LVL176:
+ 1810 0024 2053 subi r18,lo8(-(-48))
+ 1811 0026 3040 sbci r19,hi8(-(-48))
+ 1812 .LVL177:
+ 1813 .LSM143:
+ 1814 0028 2A30 cpi r18,10
+ 1815 002a 3105 cpc r19,__zero_reg__
+ 1816 002c 00F4 brsh .L96
+ 1817 .LVL178:
+ 1818 002e 8181 ldd r24,Z+1
+ 1819 0030 8A33 cpi r24,lo8(58)
+ 1820 0032 01F4 brne .L96
+ 1821 .LSM144:
+ 1822 0034 3296 adiw r30,2
+ 1823 0036 ED93 st X+,r30
+ 1824 0038 FC93 st X,r31
+ 1825 .LSM145:
+ 1826 003a 232B or r18,r19
+ 1827 003c 01F0 breq .L96
+ 1828 003e 8BE0 ldi r24,lo8(11)
+ 1829 0040 00C0 rjmp .L97
+ 1830 .L96:
+ 1831 .LSM146:
+ 1832 0042 C091 0000 lds r28,FatFs
+ 1833 0046 D091 0000 lds r29,(FatFs)+1
+ 1834 .LVL179:
+ 1835 004a FA01 movw r30,r20
+ 1836 .LVL180:
+ 1837 004c D183 std Z+1,r29
+ 1838 004e C083 st Z,r28
+ 1839 .LSM147:
+ 1840 0050 2097 sbiw r28,0
+ 1841 0052 01F4 brne .L98
+ 1842 0054 8CE0 ldi r24,lo8(12)
+ 1843 0056 00C0 rjmp .L97
+ 1844 .L98:
+ 1845 .LSM148:
+ 1846 0058 8881 ld r24,Y
+ 1847 005a 8823 tst r24
+ 1848 005c 01F0 breq .L99
+ 1849 .LSM149:
+ 1850 005e 8981 ldd r24,Y+1
+ 1851 0060 0E94 0000 call disk_status
+ 1852 .LVL181:
+ 1853 .LSM150:
+ 1854 0064 80FF sbrs r24,0
+ 1855 0066 00C0 rjmp .L112
+ 1856 .LVL182:
+ 1857 .L99:
+ 1858 .LSM151:
+ 1859 0068 1882 st Y,__zero_reg__
+ 1860 .LSM152:
+ 1861 006a 1982 std Y+1,__zero_reg__
+ 1862 .LSM153:
+ 1863 006c 80E0 ldi r24,lo8(0)
+ 1864 006e 0E94 0000 call disk_initialize
+ 1865 .LVL183:
+ 1866 .LSM154:
+ 1867 0072 80FF sbrs r24,0
+ 1868 0074 00C0 rjmp .L100
+ 1869 0076 83E0 ldi r24,lo8(3)
+ 1870 0078 00C0 rjmp .L97
+ 1871 .L100:
+ 1872 .LSM155:
+ 1873 007a CE01 movw r24,r28
+ 1874 007c 40E0 ldi r20,lo8(0)
+ 1875 007e 50E0 ldi r21,hi8(0)
+ 1876 0080 60E0 ldi r22,hlo8(0)
+ 1877 0082 70E0 ldi r23,hhi8(0)
+ 1878 0084 0E94 0000 call check_fs
+ 1879 .LSM156:
+ 1880 0088 8130 cpi r24,lo8(1)
+ 1881 .LVL184:
+ 1882 008a 01F0 breq .L101
+ 1883 008c EE24 clr r14
+ 1884 008e FF24 clr r15
+ 1885 0090 8701 movw r16,r14
+ 1886 .LVL185:
+ 1887 0092 00C0 rjmp .L102
+ 1888 .LVL186:
+ 1889 .L101:
+ 1890 .LSM157:
+ 1891 0094 FE01 movw r30,r28
+ 1892 .LVL187:
+ 1893 0096 E052 subi r30,lo8(-(480))
+ 1894 0098 FE4F sbci r31,hi8(-(480))
+ 1895 .LSM158:
+ 1896 009a 8481 ldd r24,Z+4
+ 1897 .LVL188:
+ 1898 009c 8823 tst r24
+ 1899 009e 01F4 brne .+2
+ 1900 00a0 00C0 rjmp .L103
+ 1901 .LSM159:
+ 1902 00a2 E084 ldd r14,Z+8
+ 1903 00a4 F184 ldd r15,Z+9
+ 1904 00a6 0285 ldd r16,Z+10
+ 1905 00a8 1385 ldd r17,Z+11
+ 1906 .LVL189:
+ 1907 .LSM160:
+ 1908 00aa CE01 movw r24,r28
+ 1909 00ac B801 movw r22,r16
+ 1910 00ae A701 movw r20,r14
+ 1911 00b0 0E94 0000 call check_fs
+ 1912 .LVL190:
+ 1913 .L102:
+ 1914 .LSM161:
+ 1915 00b4 8330 cpi r24,lo8(3)
+ 1916 00b6 01F4 brne .L104
+ 1917 00b8 81E0 ldi r24,lo8(1)
+ 1918 .LVL191:
+ 1919 00ba 00C0 rjmp .L97
+ 1920 .LVL192:
+ 1921 .L104:
+ 1922 .LSM162:
+ 1923 00bc 8823 tst r24
+ 1924 00be 01F0 breq .+2
+ 1925 00c0 00C0 rjmp .L103
+ 1926 00c2 8DA5 ldd r24,Y+45
+ 1927 00c4 9EA5 ldd r25,Y+46
+ 1928 .LVL193:
+ 1929 00c6 8050 subi r24,lo8(512)
+ 1930 00c8 9240 sbci r25,hi8(512)
+ 1931 00ca 01F0 breq .+2
+ 1932 00cc 00C0 rjmp .L103
+ 1933 .LSM163:
+ 1934 00ce 88AD ldd r24,Y+56
+ 1935 00d0 99AD ldd r25,Y+57
+ 1936 00d2 BC01 movw r22,r24
+ 1937 .LVL194:
+ 1938 00d4 80E0 ldi r24,lo8(0)
+ 1939 00d6 90E0 ldi r25,hi8(0)
+ 1940 .LVL195:
+ 1941 .LSM164:
+ 1942 00d8 6115 cp r22,__zero_reg__
+ 1943 00da 7105 cpc r23,__zero_reg__
+ 1944 00dc 8105 cpc r24,__zero_reg__
+ 1945 00de 9105 cpc r25,__zero_reg__
+ 1946 00e0 01F4 brne .L105
+ 1947 00e2 CA5B subi r28,lo8(-(70))
+ 1948 00e4 DF4F sbci r29,hi8(-(70))
+ 1949 00e6 6881 ld r22,Y
+ 1950 00e8 7981 ldd r23,Y+1
+ 1951 00ea 8A81 ldd r24,Y+2
+ 1952 00ec 9B81 ldd r25,Y+3
+ 1953 .LVL196:
+ 1954 00ee C654 subi r28,lo8(-(-70))
+ 1955 00f0 D040 sbci r29,hi8(-(-70))
+ 1956 .L105:
+ 1957 .LSM165:
+ 1958 00f2 6A87 std Y+10,r22
+ 1959 00f4 7B87 std Y+11,r23
+ 1960 00f6 8C87 std Y+12,r24
+ 1961 00f8 9D87 std Y+13,r25
+ 1962 .LSM166:
+ 1963 00fa 2AA9 ldd r18,Y+50
+ 1964 00fc 2B83 std Y+3,r18
+ 1965 .LSM167:
+ 1966 00fe 30E0 ldi r19,lo8(0)
+ 1967 0100 40E0 ldi r20,lo8(0)
+ 1968 0102 50E0 ldi r21,hi8(0)
+ 1969 0104 0E94 0000 call __mulsi3
+ 1970 .LVL197:
+ 1971 0108 5B01 movw r10,r22
+ 1972 010a 6C01 movw r12,r24
+ 1973 .LVL198:
+ 1974 .LSM168:
+ 1975 010c 88A9 ldd r24,Y+48
+ 1976 010e 99A9 ldd r25,Y+49
+ 1977 .LVL199:
+ 1978 0110 A0E0 ldi r26,lo8(0)
+ 1979 0112 B0E0 ldi r27,hi8(0)
+ 1980 0114 E80E add r14,r24
+ 1981 0116 F91E adc r15,r25
+ 1982 0118 0A1F adc r16,r26
+ 1983 011a 1B1F adc r17,r27
+ 1984 011c EA8A std Y+18,r14
+ 1985 011e FB8A std Y+19,r15
+ 1986 0120 0C8B std Y+20,r16
+ 1987 0122 1D8B std Y+21,r17
+ 1988 .LSM169:
+ 1989 0124 8FA5 ldd r24,Y+47
+ 1990 0126 8A83 std Y+2,r24
+ 1991 .LSM170:
+ 1992 0128 2BA9 ldd r18,Y+51
+ 1993 012a 3CA9 ldd r19,Y+52
+ 1994 012c 3987 std Y+9,r19
+ 1995 012e 2887 std Y+8,r18
+ 1996 .LSM171:
+ 1997 0130 8DA9 ldd r24,Y+53
+ 1998 0132 9EA9 ldd r25,Y+54
+ 1999 0134 7C01 movw r14,r24
+ 2000 .LVL200:
+ 2001 0136 00E0 ldi r16,lo8(0)
+ 2002 0138 10E0 ldi r17,hi8(0)
+ 2003 .LVL201:
+ 2004 .LSM172:
+ 2005 013a E114 cp r14,__zero_reg__
+ 2006 013c F104 cpc r15,__zero_reg__
+ 2007 013e 0105 cpc r16,__zero_reg__
+ 2008 0140 1105 cpc r17,__zero_reg__
+ 2009 0142 01F4 brne .L106
+ 2010 0144 CE5B subi r28,lo8(-(66))
+ 2011 0146 DF4F sbci r29,hi8(-(66))
+ 2012 0148 E880 ld r14,Y
+ 2013 014a F980 ldd r15,Y+1
+ 2014 014c 0A81 ldd r16,Y+2
+ 2015 014e 1B81 ldd r17,Y+3
+ 2016 .LVL202:
+ 2017 0150 C254 subi r28,lo8(-(-66))
+ 2018 0152 D040 sbci r29,hi8(-(-66))
+ 2019 .L106:
+ 2020 .LSM173:
+ 2021 0154 88A9 ldd r24,Y+48
+ 2022 0156 99A9 ldd r25,Y+49
+ 2023 0158 A0E0 ldi r26,lo8(0)
+ 2024 015a B0E0 ldi r27,hi8(0)
+ 2025 015c E81A sub r14,r24
+ 2026 015e F90A sbc r15,r25
+ 2027 0160 0A0B sbc r16,r26
+ 2028 0162 1B0B sbc r17,r27
+ 2029 .LVL203:
+ 2030 0164 EA18 sub r14,r10
+ 2031 0166 FB08 sbc r15,r11
+ 2032 0168 0C09 sbc r16,r12
+ 2033 016a 1D09 sbc r17,r13
+ 2034 016c 44E0 ldi r20,4
+ 2035 016e 3695 1: lsr r19
+ 2036 0170 2795 ror r18
+ 2037 0172 4A95 dec r20
+ 2038 0174 01F4 brne 1b
+ 2039 0176 C901 movw r24,r18
+ 2040 0178 A0E0 ldi r26,lo8(0)
+ 2041 017a B0E0 ldi r27,hi8(0)
+ 2042 017c E81A sub r14,r24
+ 2043 017e F90A sbc r15,r25
+ 2044 0180 0A0B sbc r16,r26
+ 2045 0182 1B0B sbc r17,r27
+ 2046 0184 2A81 ldd r18,Y+2
+ 2047 0186 30E0 ldi r19,lo8(0)
+ 2048 0188 40E0 ldi r20,lo8(0)
+ 2049 018a 50E0 ldi r21,hi8(0)
+ 2050 018c C801 movw r24,r16
+ 2051 018e B701 movw r22,r14
+ 2052 0190 0E94 0000 call __udivmodsi4
+ 2053 0194 2E5F subi r18,lo8(-(2))
+ 2054 0196 3F4F sbci r19,hi8(-(2))
+ 2055 0198 4F4F sbci r20,hlo8(-(2))
+ 2056 019a 5F4F sbci r21,hhi8(-(2))
+ 2057 .LVL204:
+ 2058 019c 2E87 std Y+14,r18
+ 2059 019e 3F87 std Y+15,r19
+ 2060 01a0 488B std Y+16,r20
+ 2061 01a2 598B std Y+17,r21
+ 2062 .LSM174:
+ 2063 01a4 273F cpi r18,lo8(4087)
+ 2064 01a6 8FE0 ldi r24,hi8(4087)
+ 2065 01a8 3807 cpc r19,r24
+ 2066 01aa 80E0 ldi r24,hlo8(4087)
+ 2067 01ac 4807 cpc r20,r24
+ 2068 01ae 80E0 ldi r24,hhi8(4087)
+ 2069 01b0 5807 cpc r21,r24
+ 2070 01b2 00F4 brsh .L107
+ 2071 01b4 61E0 ldi r22,lo8(1)
+ 2072 .LVL205:
+ 2073 01b6 00C0 rjmp .L108
+ 2074 .LVL206:
+ 2075 .L107:
+ 2076 .LSM175:
+ 2077 01b8 275F subi r18,lo8(65527)
+ 2078 01ba 3F4F sbci r19,hi8(65527)
+ 2079 01bc 4040 sbci r20,hlo8(65527)
+ 2080 01be 5040 sbci r21,hhi8(65527)
+ 2081 01c0 00F0 brlo .+2
+ 2082 01c2 00C0 rjmp .L109
+ 2083 01c4 62E0 ldi r22,lo8(2)
+ 2084 .LVL207:
+ 2085 .L108:
+ 2086 .LSM176:
+ 2087 01c6 8A89 ldd r24,Y+18
+ 2088 01c8 9B89 ldd r25,Y+19
+ 2089 01ca AC89 ldd r26,Y+20
+ 2090 01cc BD89 ldd r27,Y+21
+ 2091 01ce 8A0D add r24,r10
+ 2092 01d0 9B1D adc r25,r11
+ 2093 01d2 AC1D adc r26,r12
+ 2094 01d4 BD1D adc r27,r13
+ 2095 01d6 8E8B std Y+22,r24
+ 2096 01d8 9F8B std Y+23,r25
+ 2097 01da A88F std Y+24,r26
+ 2098 01dc B98F std Y+25,r27
+ 2099 .L110:
+ 2100 .LSM177:
+ 2101 01de 8885 ldd r24,Y+8
+ 2102 01e0 9985 ldd r25,Y+9
+ 2103 01e2 34E0 ldi r19,4
+ 2104 01e4 9695 1: lsr r25
+ 2105 01e6 8795 ror r24
+ 2106 01e8 3A95 dec r19
+ 2107 01ea 01F4 brne 1b
+ 2108 01ec A0E0 ldi r26,lo8(0)
+ 2109 01ee B0E0 ldi r27,hi8(0)
+ 2110 01f0 2A89 ldd r18,Y+18
+ 2111 01f2 3B89 ldd r19,Y+19
+ 2112 01f4 4C89 ldd r20,Y+20
+ 2113 01f6 5D89 ldd r21,Y+21
+ 2114 .LVL208:
+ 2115 01f8 820F add r24,r18
+ 2116 01fa 931F adc r25,r19
+ 2117 01fc A41F adc r26,r20
+ 2118 01fe B51F adc r27,r21
+ 2119 0200 8A0D add r24,r10
+ 2120 0202 9B1D adc r25,r11
+ 2121 0204 AC1D adc r26,r12
+ 2122 0206 BD1D adc r27,r13
+ 2123 0208 8A8F std Y+26,r24
+ 2124 020a 9B8F std Y+27,r25
+ 2125 020c AC8F std Y+28,r26
+ 2126 020e BD8F std Y+29,r27
+ 2127 .LSM178:
+ 2128 0210 6883 st Y,r22
+ 2129 .LSM179:
+ 2130 0212 1E8E std Y+30,__zero_reg__
+ 2131 0214 1F8E std Y+31,__zero_reg__
+ 2132 0216 18A2 std Y+32,__zero_reg__
+ 2133 0218 19A2 std Y+33,__zero_reg__
+ 2134 .LSM180:
+ 2135 021a 8091 0000 lds r24,Fsid
+ 2136 021e 9091 0000 lds r25,(Fsid)+1
+ 2137 0222 0196 adiw r24,1
+ 2138 0224 9093 0000 sts (Fsid)+1,r25
+ 2139 0228 8093 0000 sts Fsid,r24
+ 2140 022c 9F83 std Y+7,r25
+ 2141 022e 8E83 std Y+6,r24
+ 2142 .L112:
+ 2143 0230 80E0 ldi r24,lo8(0)
+ 2144 0232 00C0 rjmp .L97
+ 2145 .LVL209:
+ 2146 .L103:
+ 2147 .LSM181:
+ 2148 0234 8DE0 ldi r24,lo8(13)
+ 2149 .LVL210:
+ 2150 .L97:
+ 2151 /* epilogue start */
+ 2152 .LSM182:
+ 2153 0236 DF91 pop r29
+ 2154 0238 CF91 pop r28
+ 2155 .LVL211:
+ 2156 023a 1F91 pop r17
+ 2157 023c 0F91 pop r16
+ 2158 .LVL212:
+ 2159 023e FF90 pop r15
+ 2160 0240 EF90 pop r14
+ 2161 .LVL213:
+ 2162 0242 DF90 pop r13
+ 2163 0244 CF90 pop r12
+ 2164 0246 BF90 pop r11
+ 2165 0248 AF90 pop r10
+ 2166 .LVL214:
+ 2167 024a 0895 ret
+ 2168 .LVL215:
+ 2169 .L109:
+ 2170 .LSM183:
+ 2171 024c C25B subi r28,lo8(-(78))
+ 2172 024e DF4F sbci r29,hi8(-(78))
+ 2173 0250 8881 ld r24,Y
+ 2174 0252 9981 ldd r25,Y+1
+ 2175 0254 AA81 ldd r26,Y+2
+ 2176 0256 BB81 ldd r27,Y+3
+ 2177 0258 CE54 subi r28,lo8(-(-78))
+ 2178 025a D040 sbci r29,hi8(-(-78))
+ 2179 025c 8E8B std Y+22,r24
+ 2180 025e 9F8B std Y+23,r25
+ 2181 0260 A88F std Y+24,r26
+ 2182 0262 B98F std Y+25,r27
+ 2183 0264 63E0 ldi r22,lo8(3)
+ 2184 .LVL216:
+ 2185 0266 00C0 rjmp .L110
+ 2186 .LFE67:
+ 2188 .data
+ 2189 .LC0:
+ 2190 0000 2022 2A2B .string " \"*+,[=]|\177"
+ 2190 2C5B 3D5D
+ 2190 7C7F 00
+ 2191 .section .text.f_open,"ax",@progbits
+ 2192 .global f_open
+ 2194 f_open:
+ 2195 .LFB70:
+ 2196 .LSM184:
+ 2197 .LVL217:
+ 2198 0000 3F92 push r3
+ 2199 0002 4F92 push r4
+ 2200 0004 5F92 push r5
+ 2201 0006 6F92 push r6
+ 2202 0008 7F92 push r7
+ 2203 000a 8F92 push r8
+ 2204 000c 9F92 push r9
+ 2205 000e AF92 push r10
+ 2206 0010 BF92 push r11
+ 2207 0012 CF92 push r12
+ 2208 0014 DF92 push r13
+ 2209 0016 EF92 push r14
+ 2210 0018 FF92 push r15
+ 2211 001a 0F93 push r16
+ 2212 001c 1F93 push r17
+ 2213 001e DF93 push r29
+ 2214 0020 CF93 push r28
+ 2215 0022 CDB7 in r28,__SP_L__
+ 2216 0024 DEB7 in r29,__SP_H__
+ 2217 0026 A497 sbiw r28,36
+ 2218 0028 0FB6 in __tmp_reg__,__SREG__
+ 2219 002a F894 cli
+ 2220 002c DEBF out __SP_H__,r29
+ 2221 002e 0FBE out __SREG__,__tmp_reg__
+ 2222 0030 CDBF out __SP_L__,r28
+ 2223 /* prologue: function */
+ 2224 /* frame size = 36 */
+ 2225 0032 4C01 movw r8,r24
+ 2226 0034 7CA3 std Y+36,r23
+ 2227 0036 6BA3 std Y+35,r22
+ 2228 0038 742E mov r7,r20
+ 2229 .LSM185:
+ 2230 003a DC01 movw r26,r24
+ 2231 003c 1D92 st X+,__zero_reg__
+ 2232 003e 1C92 st X,__zero_reg__
+ 2233 .LSM186:
+ 2234 0040 CE01 movw r24,r28
+ 2235 .LVL218:
+ 2236 0042 8396 adiw r24,35
+ 2237 0044 BE01 movw r22,r28
+ 2238 .LVL219:
+ 2239 0046 635F subi r22,lo8(-(13))
+ 2240 0048 7F4F sbci r23,hi8(-(13))
+ 2241 004a 40E0 ldi r20,lo8(0)
+ 2242 .LVL220:
+ 2243 004c 0E94 0000 call chk_mounted
+ 2244 .LSM187:
+ 2245 0050 8823 tst r24
+ 2246 .LVL221:
+ 2247 0052 01F0 breq .+2
+ 2248 0054 00C0 rjmp .L115
+ 2249 .LSM188:
+ 2250 0056 CE01 movw r24,r28
+ 2251 .LVL222:
+ 2252 0058 0196 adiw r24,1
+ 2253 005a 9AA3 std Y+34,r25
+ 2254 005c 89A3 std Y+33,r24
+ 2255 .LSM189:
+ 2256 005e CBA0 ldd r12,Y+35
+ 2257 0060 DCA0 ldd r13,Y+36
+ 2258 .LVL223:
+ 2259 0062 00C0 rjmp .L116
+ 2260 .L117:
+ 2261 .LBB20:
+ 2262 .LBB21:
+ 2263 .LSM190:
+ 2264 0064 0894 sec
+ 2265 0066 C11C adc r12,__zero_reg__
+ 2266 0068 D11C adc r13,__zero_reg__
+ 2267 .L116:
+ 2268 006a F601 movw r30,r12
+ 2269 006c 8081 ld r24,Z
+ 2270 006e 8032 cpi r24,lo8(32)
+ 2271 0070 01F0 breq .L117
+ 2272 .LSM191:
+ 2273 0072 8F32 cpi r24,lo8(47)
+ 2274 0074 01F0 breq .L118
+ 2275 0076 8C35 cpi r24,lo8(92)
+ 2276 0078 01F4 brne .L119
+ 2277 .L118:
+ 2278 .LSM192:
+ 2279 007a 0894 sec
+ 2280 007c C11C adc r12,__zero_reg__
+ 2281 007e D11C adc r13,__zero_reg__
+ 2282 .L119:
+ 2283 .LSM193:
+ 2284 0080 1B8A std Y+19,__zero_reg__
+ 2285 0082 1C8A std Y+20,__zero_reg__
+ 2286 0084 1D8A std Y+21,__zero_reg__
+ 2287 0086 1E8A std Y+22,__zero_reg__
+ 2288 .LSM194:
+ 2289 0088 D601 movw r26,r12
+ 2290 008a 8C91 ld r24,X
+ 2291 008c 8032 cpi r24,lo8(32)
+ 2292 008e 00F4 brsh .L120
+ 2293 .LBE21:
+ 2294 .LSM195:
+ 2295 0090 CE01 movw r24,r28
+ 2296 0092 0D96 adiw r24,13
+ 2297 0094 60E0 ldi r22,lo8(0)
+ 2298 0096 70E0 ldi r23,hi8(0)
+ 2299 0098 0E94 0000 call dir_seek
+ 2300 .LBE20:
+ 2301 .LSM196:
+ 2302 009c 8823 tst r24
+ 2303 .LVL224:
+ 2304 009e 01F4 brne .+2
+ 2305 00a0 00C0 rjmp .L160
+ 2306 00a2 00C0 rjmp .L115
+ 2307 .LVL225:
+ 2308 .L120:
+ 2309 .LBB45:
+ 2310 .LBB44:
+ 2311 .LBB22:
+ 2312 .LBB24:
+ 2313 .LBB28:
+ 2314 .LBB29:
+ 2315 .LSM197:
+ 2316 00a4 F0E2 ldi r31,lo8(32)
+ 2317 00a6 6F2E mov r6,r31
+ 2318 .LBE29:
+ 2319 .LBE28:
+ 2320 .LSM198:
+ 2321 00a8 E5E0 ldi r30,lo8(5)
+ 2322 00aa 3E2E mov r3,r30
+ 2323 .LBE24:
+ 2324 .LBE22:
+ 2325 .LBB32:
+ 2326 .LSM199:
+ 2327 00ac 7DE0 ldi r23,lo8(13)
+ 2328 00ae 472E mov r4,r23
+ 2329 00b0 512C mov r5,__zero_reg__
+ 2330 00b2 4C0E add r4,r28
+ 2331 00b4 5D1E adc r5,r29
+ 2332 .LVL226:
+ 2333 .L163:
+ 2334 .LBE32:
+ 2335 .LBB41:
+ 2336 .LBB23:
+ 2337 .LSM200:
+ 2338 00b6 A9A1 ldd r26,Y+33
+ 2339 00b8 BAA1 ldd r27,Y+34
+ 2340 .LVL227:
+ 2341 00ba FD01 movw r30,r26
+ 2342 .LVL228:
+ 2343 00bc 8BE0 ldi r24,lo8(11)
+ 2344 00be 90E0 ldi r25,hi8(11)
+ 2345 .LVL229:
+ 2346 00c0 00C0 rjmp .L122
+ 2347 .LVL230:
+ 2348 .L123:
+ 2349 .LBB27:
+ 2350 .LBB30:
+ 2351 .LSM201:
+ 2352 00c2 6192 st Z+,r6
+ 2353 .L122:
+ 2354 00c4 0197 sbiw r24,1
+ 2355 00c6 2FEF ldi r18,hi8(-1)
+ 2356 00c8 8F3F cpi r24,lo8(-1)
+ 2357 00ca 9207 cpc r25,r18
+ 2358 00cc 01F4 brne .L123
+ 2359 00ce 40E0 ldi r20,lo8(0)
+ 2360 00d0 50E0 ldi r21,hi8(0)
+ 2361 .LVL231:
+ 2362 00d2 AA24 clr r10
+ 2363 00d4 BB24 clr r11
+ 2364 00d6 68E0 ldi r22,lo8(8)
+ 2365 00d8 E62E mov r14,r22
+ 2366 00da F12C mov r15,__zero_reg__
+ 2367 00dc 10E0 ldi r17,lo8(0)
+ 2368 .LVL232:
+ 2369 .L161:
+ 2370 .LBE30:
+ 2371 .LBE27:
+ 2372 .LSM202:
+ 2373 00de F601 movw r30,r12
+ 2374 00e0 EA0D add r30,r10
+ 2375 00e2 FB1D adc r31,r11
+ 2376 00e4 2081 ld r18,Z
+ 2377 00e6 0894 sec
+ 2378 00e8 A11C adc r10,__zero_reg__
+ 2379 00ea B11C adc r11,__zero_reg__
+ 2380 .LSM203:
+ 2381 00ec 2132 cpi r18,lo8(33)
+ 2382 00ee 00F4 brsh .+2
+ 2383 00f0 00C0 rjmp .L124
+ 2384 00f2 2F32 cpi r18,lo8(47)
+ 2385 00f4 01F4 brne .+2
+ 2386 00f6 00C0 rjmp .L125
+ 2387 00f8 2C35 cpi r18,lo8(92)
+ 2388 00fa 01F4 brne .+2
+ 2389 00fc 00C0 rjmp .L125
+ 2390 .LSM204:
+ 2391 00fe 2E32 cpi r18,lo8(46)
+ 2392 0100 01F0 breq .L126
+ 2393 0102 4E15 cp r20,r14
+ 2394 0104 5F05 cpc r21,r15
+ 2395 0106 04F0 brlt .L127
+ 2396 .L126:
+ 2397 .LSM205:
+ 2398 0108 88E0 ldi r24,lo8(8)
+ 2399 010a E816 cp r14,r24
+ 2400 010c F104 cpc r15,__zero_reg__
+ 2401 .LVL233:
+ 2402 010e 01F0 breq .+2
+ 2403 0110 00C0 rjmp .L128
+ 2404 0112 2E32 cpi r18,lo8(46)
+ 2405 0114 01F0 breq .+2
+ 2406 0116 00C0 rjmp .L128
+ 2407 .LSM206:
+ 2408 0118 110F lsl r17
+ 2409 011a 110F lsl r17
+ 2410 011c 48E0 ldi r20,lo8(8)
+ 2411 011e 50E0 ldi r21,hi8(8)
+ 2412 0120 3BE0 ldi r19,lo8(11)
+ 2413 0122 E32E mov r14,r19
+ 2414 0124 F12C mov r15,__zero_reg__
+ 2415 .LVL234:
+ 2416 0126 00C0 rjmp .L161
+ 2417 .LVL235:
+ 2418 .L127:
+ 2419 .LSM207:
+ 2420 0128 27FD sbrc r18,7
+ 2421 .LSM208:
+ 2422 012a 1360 ori r17,lo8(3)
+ 2423 .L130:
+ 2424 .LSM209:
+ 2425 012c 822F mov r24,r18
+ 2426 .LVL236:
+ 2427 012e 8158 subi r24,lo8(-(127))
+ 2428 0130 8F31 cpi r24,lo8(31)
+ 2429 0132 00F0 brlo .L131
+ 2430 0134 8F55 subi r24,lo8(-(-95))
+ 2431 0136 8D31 cpi r24,lo8(29)
+ 2432 0138 00F4 brsh .L132
+ 2433 .L131:
+ 2434 .LSM210:
+ 2435 013a F601 movw r30,r12
+ 2436 013c EA0D add r30,r10
+ 2437 013e FB1D adc r31,r11
+ 2438 0140 3081 ld r19,Z
+ 2439 .LSM211:
+ 2440 0142 832F mov r24,r19
+ 2441 0144 8054 subi r24,lo8(-(-64))
+ 2442 0146 8F33 cpi r24,lo8(63)
+ 2443 0148 00F0 brlo .L133
+ 2444 014a 8054 subi r24,lo8(-(-64))
+ 2445 014c 8D37 cpi r24,lo8(125)
+ 2446 014e 00F0 brlo .+2
+ 2447 0150 00C0 rjmp .L128
+ 2448 .L133:
+ 2449 0152 C701 movw r24,r14
+ 2450 0154 0197 sbiw r24,1
+ 2451 0156 4817 cp r20,r24
+ 2452 0158 5907 cpc r21,r25
+ 2453 015a 04F0 brlt .+2
+ 2454 015c 00C0 rjmp .L128
+ 2455 .LSM212:
+ 2456 015e 0894 sec
+ 2457 0160 A11C adc r10,__zero_reg__
+ 2458 0162 B11C adc r11,__zero_reg__
+ 2459 .LSM213:
+ 2460 0164 FD01 movw r30,r26
+ 2461 0166 E40F add r30,r20
+ 2462 0168 F51F adc r31,r21
+ 2463 016a 2083 st Z,r18
+ 2464 016c CA01 movw r24,r20
+ 2465 016e 0196 adiw r24,1
+ 2466 .LVL237:
+ 2467 .LSM214:
+ 2468 0170 FD01 movw r30,r26
+ 2469 0172 E80F add r30,r24
+ 2470 0174 F91F adc r31,r25
+ 2471 0176 3083 st Z,r19
+ 2472 0178 AC01 movw r20,r24
+ 2473 017a 00C0 rjmp .L164
+ 2474 .LVL238:
+ 2475 .L132:
+ 2476 .LSM215:
+ 2477 017c 622F mov r22,r18
+ 2478 017e 70E0 ldi r23,lo8(0)
+ 2479 0180 E0E0 ldi r30,lo8(.LC0)
+ 2480 0182 F0E0 ldi r31,hi8(.LC0)
+ 2481 .LVL239:
+ 2482 0184 00C0 rjmp .L134
+ 2483 .LVL240:
+ 2484 .L136:
+ 2485 .LBB25:
+ 2486 .LBB26:
+ 2487 .LSM216:
+ 2488 0186 3196 adiw r30,1
+ 2489 .LVL241:
+ 2490 .L134:
+ 2491 0188 8081 ld r24,Z
+ 2492 018a 8823 tst r24
+ 2493 018c 01F0 breq .L135
+ 2494 018e 90E0 ldi r25,lo8(0)
+ 2495 .LVL242:
+ 2496 0190 8617 cp r24,r22
+ 2497 0192 9707 cpc r25,r23
+ 2498 0194 01F4 brne .L136
+ 2499 0196 00C0 rjmp .L128
+ 2500 .LVL243:
+ 2501 .L135:
+ 2502 .LBE26:
+ 2503 .LBE25:
+ 2504 .LSM217:
+ 2505 0198 822F mov r24,r18
+ 2506 019a 8154 subi r24,lo8(-(-65))
+ 2507 019c 8A31 cpi r24,lo8(26)
+ 2508 019e 00F4 brsh .L137
+ 2509 .LSM218:
+ 2510 01a0 1260 ori r17,lo8(2)
+ 2511 01a2 00C0 rjmp .L138
+ 2512 .L137:
+ 2513 .LSM219:
+ 2514 01a4 822F mov r24,r18
+ 2515 01a6 8156 subi r24,lo8(-(-97))
+ 2516 01a8 8A31 cpi r24,lo8(26)
+ 2517 01aa 00F4 brsh .L138
+ 2518 .LSM220:
+ 2519 01ac 1160 ori r17,lo8(1)
+ 2520 01ae 2052 subi r18,lo8(-(-32))
+ 2521 .L138:
+ 2522 .LSM221:
+ 2523 01b0 FD01 movw r30,r26
+ 2524 .LVL244:
+ 2525 01b2 E40F add r30,r20
+ 2526 01b4 F51F adc r31,r21
+ 2527 01b6 2083 st Z,r18
+ 2528 .LVL245:
+ 2529 .L164:
+ 2530 01b8 4F5F subi r20,lo8(-(1))
+ 2531 01ba 5F4F sbci r21,hi8(-(1))
+ 2532 01bc 00C0 rjmp .L161
+ 2533 .LVL246:
+ 2534 .L124:
+ 2535 01be 912F mov r25,r17
+ 2536 .LVL247:
+ 2537 01c0 64E0 ldi r22,lo8(4)
+ 2538 .LVL248:
+ 2539 .L158:
+ 2540 .LSM222:
+ 2541 01c2 452B or r20,r21
+ 2542 01c4 01F4 brne .+2
+ 2543 01c6 00C0 rjmp .L128
+ 2544 .LSM223:
+ 2545 01c8 8C91 ld r24,X
+ 2546 .LVL249:
+ 2547 01ca 853E cpi r24,lo8(-27)
+ 2548 01cc 01F4 brne .L139
+ 2549 01ce 3C92 st X,r3
+ 2550 .L139:
+ 2551 .LSM224:
+ 2552 01d0 E8E0 ldi r30,lo8(8)
+ 2553 01d2 EE16 cp r14,r30
+ 2554 01d4 F104 cpc r15,__zero_reg__
+ 2555 01d6 01F4 brne .L140
+ 2556 01d8 912F mov r25,r17
+ 2557 01da 990F lsl r25
+ 2558 01dc 990F lsl r25
+ 2559 .LVL250:
+ 2560 .L140:
+ 2561 .LSM225:
+ 2562 01de 292F mov r18,r25
+ 2563 01e0 30E0 ldi r19,lo8(0)
+ 2564 .LVL251:
+ 2565 01e2 C901 movw r24,r18
+ 2566 01e4 8370 andi r24,lo8(3)
+ 2567 01e6 9070 andi r25,hi8(3)
+ 2568 01e8 0197 sbiw r24,1
+ 2569 01ea 01F4 brne .L141
+ 2570 01ec 6061 ori r22,lo8(16)
+ 2571 .L141:
+ 2572 .LSM226:
+ 2573 01ee 2C70 andi r18,lo8(12)
+ 2574 01f0 3070 andi r19,hi8(12)
+ 2575 01f2 2430 cpi r18,4
+ 2576 01f4 3105 cpc r19,__zero_reg__
+ 2577 01f6 01F4 brne .L142
+ 2578 01f8 6860 ori r22,lo8(8)
+ 2579 .L142:
+ 2580 .LSM227:
+ 2581 01fa 1B96 adiw r26,11
+ 2582 01fc 6C93 st X,r22
+ 2583 .LBE23:
+ 2584 .LBE41:
+ 2585 .LBB42:
+ 2586 .LSM228:
+ 2587 01fe C201 movw r24,r4
+ 2588 0200 60E0 ldi r22,lo8(0)
+ 2589 0202 70E0 ldi r23,hi8(0)
+ 2590 .LVL252:
+ 2591 0204 0E94 0000 call dir_seek
+ 2592 .LVL253:
+ 2593 0208 482F mov r20,r24
+ 2594 .LVL254:
+ 2595 .LBB33:
+ 2596 .LSM229:
+ 2597 020a 8823 tst r24
+ 2598 020c 01F0 breq .+2
+ 2599 020e 00C0 rjmp .L143
+ 2600 .LVL255:
+ 2601 .L162:
+ 2602 .LBE33:
+ 2603 .LSM230:
+ 2604 0210 4B8D ldd r20,Y+27
+ 2605 0212 5C8D ldd r21,Y+28
+ 2606 0214 6D8D ldd r22,Y+29
+ 2607 0216 7E8D ldd r23,Y+30
+ 2608 .LVL256:
+ 2609 0218 8D85 ldd r24,Y+13
+ 2610 021a 9E85 ldd r25,Y+14
+ 2611 .LVL257:
+ 2612 021c 0E94 0000 call move_window
+ 2613 .LVL258:
+ 2614 0220 482F mov r20,r24
+ 2615 .LVL259:
+ 2616 .LBB40:
+ 2617 .LSM231:
+ 2618 0222 8823 tst r24
+ 2619 0224 01F0 breq .+2
+ 2620 0226 00C0 rjmp .L143
+ 2621 .LVL260:
+ 2622 .LSM232:
+ 2623 0228 EF8D ldd r30,Y+31
+ 2624 022a F8A1 ldd r31,Y+32
+ 2625 .LVL261:
+ 2626 .LSM233:
+ 2627 022c 8081 ld r24,Z
+ 2628 .LVL262:
+ 2629 022e 8823 tst r24
+ 2630 0230 01F4 brne .+2
+ 2631 0232 00C0 rjmp .L147
+ 2632 .L144:
+ 2633 .LSM234:
+ 2634 0234 8385 ldd r24,Z+11
+ 2635 0236 83FD sbrc r24,3
+ 2636 0238 00C0 rjmp .L145
+ 2637 023a 89A1 ldd r24,Y+33
+ 2638 .LVL263:
+ 2639 023c 9AA1 ldd r25,Y+34
+ 2640 .LVL264:
+ 2641 023e 9C01 movw r18,r24
+ 2642 .LVL265:
+ 2643 0240 D901 movw r26,r18
+ 2644 .LVL266:
+ 2645 0242 2BE0 ldi r18,lo8(11)
+ 2646 0244 30E0 ldi r19,hi8(11)
+ 2647 .LVL267:
+ 2648 .L146:
+ 2649 .LBB34:
+ 2650 .LBB35:
+ 2651 .LSM235:
+ 2652 0246 2150 subi r18,lo8(-(-1))
+ 2653 0248 3040 sbci r19,hi8(-(-1))
+ 2654 024a 8FEF ldi r24,hi8(-1)
+ 2655 024c 2F3F cpi r18,lo8(-1)
+ 2656 024e 3807 cpc r19,r24
+ 2657 0250 01F4 brne .+2
+ 2658 0252 00C0 rjmp .L143
+ 2659 0254 9081 ld r25,Z
+ 2660 .LVL268:
+ 2661 0256 8C91 ld r24,X
+ 2662 0258 9817 cp r25,r24
+ 2663 025a 01F4 brne .L145
+ 2664 025c 3196 adiw r30,1
+ 2665 .LVL269:
+ 2666 025e 1196 adiw r26,1
+ 2667 0260 00C0 rjmp .L146
+ 2668 .LVL270:
+ 2669 .L145:
+ 2670 .LBE35:
+ 2671 .LBE34:
+ 2672 .LBB36:
+ 2673 .LBB37:
+ 2674 .LSM236:
+ 2675 0262 0989 ldd r16,Y+17
+ 2676 0264 1A89 ldd r17,Y+18
+ 2677 0266 0F5F subi r16,lo8(-(1))
+ 2678 0268 1F4F sbci r17,hi8(-(1))
+ 2679 .LSM237:
+ 2680 026a 01F4 brne .+2
+ 2681 026c 00C0 rjmp .L147
+ 2682 026e 8B8D ldd r24,Y+27
+ 2683 0270 9C8D ldd r25,Y+28
+ 2684 0272 AD8D ldd r26,Y+29
+ 2685 0274 BE8D ldd r27,Y+30
+ 2686 0276 0097 sbiw r24,0
+ 2687 0278 A105 cpc r26,__zero_reg__
+ 2688 027a B105 cpc r27,__zero_reg__
+ 2689 027c 01F4 brne .+2
+ 2690 027e 00C0 rjmp .L147
+ 2691 .LSM238:
+ 2692 0280 2FE0 ldi r18,lo8(15)
+ 2693 0282 E22E mov r14,r18
+ 2694 0284 F12C mov r15,__zero_reg__
+ 2695 .LVL271:
+ 2696 0286 E022 and r14,r16
+ 2697 0288 F122 and r15,r17
+ 2698 028a E114 cp r14,__zero_reg__
+ 2699 028c F104 cpc r15,__zero_reg__
+ 2700 028e 01F0 breq .+2
+ 2701 0290 00C0 rjmp .L148
+ 2702 .LSM239:
+ 2703 0292 0196 adiw r24,1
+ 2704 0294 A11D adc r26,__zero_reg__
+ 2705 0296 B11D adc r27,__zero_reg__
+ 2706 0298 8B8F std Y+27,r24
+ 2707 029a 9C8F std Y+28,r25
+ 2708 029c AD8F std Y+29,r26
+ 2709 029e BE8F std Y+30,r27
+ 2710 .LSM240:
+ 2711 02a0 4F89 ldd r20,Y+23
+ 2712 02a2 588D ldd r21,Y+24
+ 2713 02a4 698D ldd r22,Y+25
+ 2714 02a6 7A8D ldd r23,Y+26
+ 2715 .LVL272:
+ 2716 02a8 ED85 ldd r30,Y+13
+ 2717 02aa FE85 ldd r31,Y+14
+ 2718 .LVL273:
+ 2719 02ac 4115 cp r20,__zero_reg__
+ 2720 02ae 5105 cpc r21,__zero_reg__
+ 2721 02b0 6105 cpc r22,__zero_reg__
+ 2722 02b2 7105 cpc r23,__zero_reg__
+ 2723 02b4 01F4 brne .L149
+ 2724 .LSM241:
+ 2725 02b6 8085 ldd r24,Z+8
+ 2726 02b8 9185 ldd r25,Z+9
+ 2727 02ba 0817 cp r16,r24
+ 2728 02bc 1907 cpc r17,r25
+ 2729 02be 00F0 brlo .L148
+ 2730 02c0 00C0 rjmp .L147
+ 2731 .L149:
+ 2732 .LSM242:
+ 2733 02c2 8281 ldd r24,Z+2
+ 2734 02c4 90E0 ldi r25,lo8(0)
+ 2735 02c6 0197 sbiw r24,1
+ 2736 02c8 9801 movw r18,r16
+ 2737 02ca A4E0 ldi r26,4
+ 2738 02cc 3695 1: lsr r19
+ 2739 02ce 2795 ror r18
+ 2740 02d0 AA95 dec r26
+ 2741 02d2 01F4 brne 1b
+ 2742 .LVL274:
+ 2743 02d4 8223 and r24,r18
+ 2744 02d6 9323 and r25,r19
+ 2745 02d8 892B or r24,r25
+ 2746 02da 01F4 brne .L148
+ 2747 .LBE37:
+ 2748 .LSM243:
+ 2749 02dc CF01 movw r24,r30
+ 2750 02de 0E94 0000 call get_fat
+ 2751 02e2 AB01 movw r20,r22
+ 2752 02e4 BC01 movw r22,r24
+ 2753 .LVL275:
+ 2754 .LBB38:
+ 2755 .LSM244:
+ 2756 02e6 4230 cpi r20,lo8(2)
+ 2757 02e8 5105 cpc r21,__zero_reg__
+ 2758 02ea 6105 cpc r22,__zero_reg__
+ 2759 02ec 7105 cpc r23,__zero_reg__
+ 2760 02ee 00F4 brsh .L150
+ 2761 02f0 42E0 ldi r20,lo8(2)
+ 2762 .LVL276:
+ 2763 02f2 00C0 rjmp .L143
+ 2764 .LVL277:
+ 2765 .L150:
+ 2766 .LSM245:
+ 2767 02f4 4F3F cpi r20,lo8(-1)
+ 2768 02f6 9FEF ldi r25,hi8(-1)
+ 2769 02f8 5907 cpc r21,r25
+ 2770 02fa 9FEF ldi r25,hlo8(-1)
+ 2771 02fc 6907 cpc r22,r25
+ 2772 02fe 9FEF ldi r25,hhi8(-1)
+ 2773 0300 7907 cpc r23,r25
+ 2774 0302 01F4 brne .L151
+ 2775 0304 41E0 ldi r20,lo8(1)
+ 2776 .LVL278:
+ 2777 0306 00C0 rjmp .L143
+ 2778 .LVL279:
+ 2779 .L151:
+ 2780 .LSM246:
+ 2781 0308 ED85 ldd r30,Y+13
+ 2782 030a FE85 ldd r31,Y+14
+ 2783 030c 8685 ldd r24,Z+14
+ 2784 030e 9785 ldd r25,Z+15
+ 2785 0310 A089 ldd r26,Z+16
+ 2786 0312 B189 ldd r27,Z+17
+ 2787 0314 4817 cp r20,r24
+ 2788 0316 5907 cpc r21,r25
+ 2789 0318 6A07 cpc r22,r26
+ 2790 031a 7B07 cpc r23,r27
+ 2791 031c 00F4 brsh .L147
+ 2792 .LSM247:
+ 2793 031e 4F8B std Y+23,r20
+ 2794 0320 588F std Y+24,r21
+ 2795 0322 698F std Y+25,r22
+ 2796 0324 7A8F std Y+26,r23
+ 2797 .LBE38:
+ 2798 .LSM248:
+ 2799 0326 CF01 movw r24,r30
+ 2800 0328 0E94 0000 call clust2sect
+ 2801 .LVL280:
+ 2802 .LBB39:
+ 2803 032c 6B8F std Y+27,r22
+ 2804 032e 7C8F std Y+28,r23
+ 2805 0330 8D8F std Y+29,r24
+ 2806 0332 9E8F std Y+30,r25
+ 2807 .LVL281:
+ 2808 .L148:
+ 2809 .LSM249:
+ 2810 0334 1A8B std Y+18,r17
+ 2811 0336 098B std Y+17,r16
+ 2812 .LSM250:
+ 2813 0338 75E0 ldi r23,5
+ 2814 033a EE0C 1: lsl r14
+ 2815 033c FF1C rol r15
+ 2816 033e 7A95 dec r23
+ 2817 0340 01F4 brne 1b
+ 2818 0342 A2E2 ldi r26,lo8(34)
+ 2819 0344 B0E0 ldi r27,hi8(34)
+ 2820 .LVL282:
+ 2821 0346 EA0E add r14,r26
+ 2822 0348 FB1E adc r15,r27
+ 2823 034a 8D85 ldd r24,Y+13
+ 2824 034c 9E85 ldd r25,Y+14
+ 2825 034e 8E0D add r24,r14
+ 2826 0350 9F1D adc r25,r15
+ 2827 0352 98A3 std Y+32,r25
+ 2828 0354 8F8F std Y+31,r24
+ 2829 0356 00C0 rjmp .L162
+ 2830 .LVL283:
+ 2831 .L147:
+ 2832 0358 44E0 ldi r20,lo8(4)
+ 2833 .LVL284:
+ 2834 .L143:
+ 2835 .LBE39:
+ 2836 .LBE36:
+ 2837 .LBE40:
+ 2838 .LBE42:
+ 2839 .LSM251:
+ 2840 035a E9A1 ldd r30,Y+33
+ 2841 035c FAA1 ldd r31,Y+34
+ 2842 .LVL285:
+ 2843 035e 9385 ldd r25,Z+11
+ 2844 .LVL286:
+ 2845 0360 9470 andi r25,lo8(4)
+ 2846 .LSM252:
+ 2847 0362 4423 tst r20
+ 2848 0364 01F0 breq .L153
+ 2849 0366 842F mov r24,r20
+ 2850 .LSM253:
+ 2851 0368 4430 cpi r20,lo8(4)
+ 2852 036a 01F0 breq .+2
+ 2853 036c 00C0 rjmp .L115
+ 2854 036e 9923 tst r25
+ 2855 0370 01F4 brne .+2
+ 2856 0372 00C0 rjmp .L155
+ 2857 0374 00C0 rjmp .L115
+ 2858 .L153:
+ 2859 .LSM254:
+ 2860 0376 9923 tst r25
+ 2861 0378 01F4 brne .L156
+ 2862 .LSM255:
+ 2863 037a EF8D ldd r30,Y+31
+ 2864 037c F8A1 ldd r31,Y+32
+ 2865 .LVL287:
+ 2866 .LSM256:
+ 2867 037e 8385 ldd r24,Z+11
+ 2868 0380 84FF sbrs r24,4
+ 2869 0382 00C0 rjmp .L155
+ 2870 .LBB43:
+ 2871 .LBB31:
+ 2872 .LSM257:
+ 2873 0384 CA0C add r12,r10
+ 2874 0386 DB1C adc r13,r11
+ 2875 .LBE31:
+ 2876 .LBE43:
+ 2877 .LSM258:
+ 2878 0388 8489 ldd r24,Z+20
+ 2879 038a 9589 ldd r25,Z+21
+ 2880 038c A0E0 ldi r26,lo8(0)
+ 2881 038e B0E0 ldi r27,hi8(0)
+ 2882 .LVL288:
+ 2883 0390 DC01 movw r26,r24
+ 2884 0392 9927 clr r25
+ 2885 0394 8827 clr r24
+ 2886 0396 228D ldd r18,Z+26
+ 2887 0398 338D ldd r19,Z+27
+ 2888 .LVL289:
+ 2889 039a 40E0 ldi r20,lo8(0)
+ 2890 039c 50E0 ldi r21,hi8(0)
+ 2891 .LVL290:
+ 2892 039e 822B or r24,r18
+ 2893 03a0 932B or r25,r19
+ 2894 03a2 A42B or r26,r20
+ 2895 03a4 B52B or r27,r21
+ 2896 03a6 8B8B std Y+19,r24
+ 2897 03a8 9C8B std Y+20,r25
+ 2898 03aa AD8B std Y+21,r26
+ 2899 03ac BE8B std Y+22,r27
+ 2900 03ae 00C0 rjmp .L163
+ 2901 .LVL291:
+ 2902 .L160:
+ 2903 .LSM259:
+ 2904 03b0 18A2 std Y+32,__zero_reg__
+ 2905 03b2 1F8E std Y+31,__zero_reg__
+ 2906 .LVL292:
+ 2907 .L156:
+ 2908 .LBE44:
+ 2909 .LBE45:
+ 2910 .LSM260:
+ 2911 03b4 EF8D ldd r30,Y+31
+ 2912 03b6 F8A1 ldd r31,Y+32
+ 2913 .LVL293:
+ 2914 .LSM261:
+ 2915 03b8 3097 sbiw r30,0
+ 2916 03ba 01F4 brne .+2
+ 2917 03bc 00C0 rjmp .L157
+ 2918 03be 8385 ldd r24,Z+11
+ 2919 .LVL294:
+ 2920 03c0 84FD sbrc r24,4
+ 2921 03c2 00C0 rjmp .L157
+ 2922 .LSM262:
+ 2923 03c4 B1E0 ldi r27,lo8(1)
+ 2924 03c6 7B22 and r7,r27
+ 2925 03c8 D401 movw r26,r8
+ 2926 .LVL295:
+ 2927 03ca 1496 adiw r26,4
+ 2928 03cc 7C92 st X,r7
+ 2929 .LSM263:
+ 2930 03ce 8489 ldd r24,Z+20
+ 2931 03d0 9589 ldd r25,Z+21
+ 2932 03d2 A0E0 ldi r26,lo8(0)
+ 2933 03d4 B0E0 ldi r27,hi8(0)
+ 2934 03d6 8C01 movw r16,r24
+ 2935 03d8 FF24 clr r15
+ 2936 03da EE24 clr r14
+ 2937 .LVL296:
+ 2938 03dc 228D ldd r18,Z+26
+ 2939 03de 338D ldd r19,Z+27
+ 2940 .LVL297:
+ 2941 03e0 40E0 ldi r20,lo8(0)
+ 2942 03e2 50E0 ldi r21,hi8(0)
+ 2943 .LVL298:
+ 2944 03e4 E22A or r14,r18
+ 2945 03e6 F32A or r15,r19
+ 2946 03e8 042B or r16,r20
+ 2947 03ea 152B or r17,r21
+ 2948 03ec D401 movw r26,r8
+ 2949 03ee 1E96 adiw r26,14
+ 2950 03f0 ED92 st X+,r14
+ 2951 03f2 FD92 st X+,r15
+ 2952 03f4 0D93 st X+,r16
+ 2953 03f6 1C93 st X,r17
+ 2954 03f8 5197 sbiw r26,14+3
+ 2955 .LSM264:
+ 2956 03fa 848D ldd r24,Z+28
+ 2957 03fc 958D ldd r25,Z+29
+ 2958 03fe A68D ldd r26,Z+30
+ 2959 0400 B78D ldd r27,Z+31
+ 2960 0402 F401 movw r30,r8
+ 2961 .LVL299:
+ 2962 0404 8287 std Z+10,r24
+ 2963 0406 9387 std Z+11,r25
+ 2964 0408 A487 std Z+12,r26
+ 2965 040a B587 std Z+13,r27
+ 2966 .LSM265:
+ 2967 040c D401 movw r26,r8
+ 2968 040e 1696 adiw r26,6
+ 2969 0410 1D92 st X+,__zero_reg__
+ 2970 0412 1D92 st X+,__zero_reg__
+ 2971 0414 1D92 st X+,__zero_reg__
+ 2972 0416 1C92 st X,__zero_reg__
+ 2973 0418 1997 sbiw r26,6+3
+ 2974 041a 8FEF ldi r24,lo8(-1)
+ 2975 041c 1596 adiw r26,5
+ 2976 041e 8C93 st X,r24
+ 2977 0420 1597 sbiw r26,5
+ 2978 .LSM266:
+ 2979 0422 168A std Z+22,__zero_reg__
+ 2980 0424 178A std Z+23,__zero_reg__
+ 2981 0426 108E std Z+24,__zero_reg__
+ 2982 0428 118E std Z+25,__zero_reg__
+ 2983 .LSM267:
+ 2984 042a ED85 ldd r30,Y+13
+ 2985 042c FE85 ldd r31,Y+14
+ 2986 042e 1196 adiw r26,1
+ 2987 0430 FC93 st X,r31
+ 2988 0432 EE93 st -X,r30
+ 2989 0434 8681 ldd r24,Z+6
+ 2990 0436 9781 ldd r25,Z+7
+ 2991 0438 1396 adiw r26,2+1
+ 2992 043a 9C93 st X,r25
+ 2993 043c 8E93 st -X,r24
+ 2994 043e 1297 sbiw r26,2
+ 2995 0440 80E0 ldi r24,lo8(0)
+ 2996 .LVL300:
+ 2997 0442 00C0 rjmp .L115
+ 2998 .LVL301:
+ 2999 .L157:
+ 3000 .LSM268:
+ 3001 0444 84E0 ldi r24,lo8(4)
+ 3002 .LVL302:
+ 3003 .L115:
+ 3004 .LVL303:
+ 3005 /* epilogue start */
+ 3006 .LSM269:
+ 3007 0446 A496 adiw r28,36
+ 3008 0448 0FB6 in __tmp_reg__,__SREG__
+ 3009 044a F894 cli
+ 3010 044c DEBF out __SP_H__,r29
+ 3011 044e 0FBE out __SREG__,__tmp_reg__
+ 3012 0450 CDBF out __SP_L__,r28
+ 3013 0452 CF91 pop r28
+ 3014 0454 DF91 pop r29
+ 3015 0456 1F91 pop r17
+ 3016 .LVL304:
+ 3017 0458 0F91 pop r16
+ 3018 .LVL305:
+ 3019 045a FF90 pop r15
+ 3020 045c EF90 pop r14
+ 3021 .LVL306:
+ 3022 045e DF90 pop r13
+ 3023 0460 CF90 pop r12
+ 3024 .LVL307:
+ 3025 0462 BF90 pop r11
+ 3026 0464 AF90 pop r10
+ 3027 .LVL308:
+ 3028 0466 9F90 pop r9
+ 3029 0468 8F90 pop r8
+ 3030 .LVL309:
+ 3031 046a 7F90 pop r7
+ 3032 .LVL310:
+ 3033 046c 6F90 pop r6
+ 3034 046e 5F90 pop r5
+ 3035 0470 4F90 pop r4
+ 3036 0472 3F90 pop r3
+ 3037 0474 0895 ret
+ 3038 .LVL311:
+ 3039 .L155:
+ 3040 .LSM270:
+ 3041 0476 85E0 ldi r24,lo8(5)
+ 3042 .LVL312:
+ 3043 0478 00C0 rjmp .L115
+ 3044 .LVL313:
+ 3045 .L128:
+ 3046 047a 86E0 ldi r24,lo8(6)
+ 3047 .LVL314:
+ 3048 047c 00C0 rjmp .L115
+ 3049 .LVL315:
+ 3050 .L125:
+ 3051 047e 912F mov r25,r17
+ 3052 .LVL316:
+ 3053 0480 60E0 ldi r22,lo8(0)
+ 3054 .LVL317:
+ 3055 0482 00C0 rjmp .L158
+ 3056 .LFE70:
+ 3058 .lcomm FatFs,2
+ 3059 .lcomm Fsid,2
+ 3172 .Letext0:
+DEFINED SYMBOLS
+ *ABS*:00000000 ff.c
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:2 *ABS*:0000003f __SREG__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:3 *ABS*:0000003e __SP_H__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:4 *ABS*:0000003d __SP_L__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:5 *ABS*:00000034 __CCP__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:6 *ABS*:00000000 __tmp_reg__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:7 *ABS*:00000001 __zero_reg__
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:19 .text.clust2sect:00000000 clust2sect
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:101 .text.f_mount:00000000 f_mount
+ .bss:00000000 FatFs
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:144 .text.validate:00000000 validate
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:184 .text.f_close:00000000 f_close
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:218 .text.move_window:00000000 move_window
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:292 .text.get_fat:00000000 get_fat
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:545 .text.f_lseek:00000000 f_lseek
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:1021 .text.dir_seek:00000000 dir_seek
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:1270 .text.f_read:00000000 f_read
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:1694 .text.check_fs:00000000 check_fs
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:1779 .text.chk_mounted:00000000 chk_mounted
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:3058 .bss:00000002 Fsid
+C:\Users\Dean\AppData\Local\Temp/cchqutwM.s:2194 .text.f_open:00000000 f_open
+
+UNDEFINED SYMBOLS
+__mulsi3
+disk_status
+disk_read
+__udivmodsi4
+disk_initialize
+__do_copy_data
+__do_clear_bss
diff --git a/Projects/Webserver/Lib/FATFs/ffconf.h b/Projects/Webserver/Lib/FATFs/ffconf.h
new file mode 100644
index 000000000..4b19f1326
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/ffconf.h
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module configuration file R0.07e (C)ChaN, 2010
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONFIG
+#define _FFCONFIG 0x007E
+
+
+/*---------------------------------------------------------------------------/
+/ Function and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define _FS_TINY 1 /* 0 or 1 */
+/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
+/ object instead of the sector buffer in the individual file object for file
+/ data transfer. This reduces memory consumption 512 bytes each file object. */
+
+
+#define _FS_READONLY 1 /* 0 or 1 */
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
+/ f_truncate and useless f_getfree. */
+
+
+#define _FS_MINIMIZE 2 /* 0, 1, 2 or 3 */
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/
+/ 0: Full function.
+/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
+/ are removed.
+/ 2: f_opendir and f_readdir are removed in addition to level 1.
+/ 3: f_lseek is removed in addition to level 2. */
+
+
+#define _USE_STRFUNC 0 /* 0, 1 or 2 */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define _USE_MKFS 0 /* 0 or 1 */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define _USE_FORWARD 0 /* 0 or 1 */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE 932
+/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
+/ Incorrect setting of the code page can cause a file open failure.
+/
+/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
+/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
+/ 949 - Korean (DBCS, OEM, Windows)
+/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/ 1250 - Central Europe (Windows)
+/ 1251 - Cyrillic (Windows)
+/ 1252 - Latin 1 (Windows)
+/ 1253 - Greek (Windows)
+/ 1254 - Turkish (Windows)
+/ 1255 - Hebrew (Windows)
+/ 1256 - Arabic (Windows)
+/ 1257 - Baltic (Windows)
+/ 1258 - Vietnam (OEM, Windows)
+/ 437 - U.S. (OEM)
+/ 720 - Arabic (OEM)
+/ 737 - Greek (OEM)
+/ 775 - Baltic (OEM)
+/ 850 - Multilingual Latin 1 (OEM)
+/ 858 - Multilingual Latin 1 + Euro (OEM)
+/ 852 - Latin 2 (OEM)
+/ 855 - Cyrillic (OEM)
+/ 866 - Russian (OEM)
+/ 857 - Turkish (OEM)
+/ 862 - Hebrew (OEM)
+/ 874 - Thai (OEM, Windows)
+/ 1 - ASCII only (Valid for non LFN cfg.)
+*/
+
+
+#define _USE_LFN 0 /* 0, 1 or 2 */
+#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN option switches the LFN support.
+/
+/ 0: Disable LFN. _MAX_LFN and _LFN_UNICODE have no effect.
+/ 1: Enable LFN with static working buffer on the bss. NOT REENTRANT.
+/ 2: Enable LFN with dynamic working buffer on the STACK.
+/
+/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. When enable LFN,
+/ two Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/ to the project. */
+
+
+#define _LFN_UNICODE 0 /* 0 or 1 */
+/* To switch the character code set on FatFs API to Unicode,
+/ enable LFN feature and set _LFN_UNICODE to 1.
+*/
+
+
+#define _FS_RPATH 0 /* 0 or 1 */
+/* When _FS_RPATH is set to 1, relative path feature is enabled and f_chdir,
+/ f_chdrive function are available.
+/ Note that output of the f_readdir fnction is affected by this option. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _DRIVES 1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
+/* Maximum sector size to be handled.
+/ Always set 512 for memory card and hard disk but a larger value may be
+/ required for floppy disk (512/1024) and optical disk (512/2048).
+/ When _MAX_SS is larger than 512, GET_SECTOR_SIZE command must be implememted
+/ to the disk_ioctl function. */
+
+
+#define _MULTI_PARTITION 0 /* 0 or 1 */
+/* When _MULTI_PARTITION is set to 0, each volume is bound to the same physical
+/ drive number and can mount only first primaly partition. When it is set to 1,
+/ each volume is tied to the partitions listed in Drives[]. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS 1 /* 0 or 1 */
+/* The _WORD_ACCESS option defines which access method is used to the word
+/ data on the FAT volume.
+/
+/ 0: Byte-by-byte access. Always compatible with all platforms.
+/ 1: Word access. Do not choose this unless following condition is met.
+/
+/ When the byte order on the memory is big-endian or address miss-aligned
+/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/ If it is not the case, the value can also be set to 1 to improve the
+/ performance and code size. */
+
+
+#define _FS_REENTRANT 0 /* 0 or 1 */
+#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
+#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
+/* The _FS_REENTRANT option switches the reentrancy of the FatFs module.
+/
+/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
+/ 1: Enable reentrancy. Also user provided synchronization handlers,
+/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
+/ function must be added to the project. */
+
+
+#endif /* _FFCONFIG */
diff --git a/Projects/Webserver/Lib/FATFs/integer.h b/Projects/Webserver/Lib/FATFs/integer.h
new file mode 100644
index 000000000..1d6bac368
--- /dev/null
+++ b/Projects/Webserver/Lib/FATFs/integer.h
@@ -0,0 +1,37 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+
+#if 0
+#include <windows.h>
+#else
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int INT;
+typedef unsigned int UINT;
+
+/* These types must be 8-bit integer */
+typedef signed char CHAR;
+typedef unsigned char UCHAR;
+typedef unsigned char BYTE;
+
+/* These types must be 16-bit integer */
+typedef short SHORT;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned short WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef unsigned long DWORD;
+
+/* Boolean type */
+typedef enum { FALSE = 0, TRUE } BOOL;
+
+#endif
+
+#define _INTEGER
+#endif
diff --git a/Projects/Webserver/Lib/HTTPServerApp.c b/Projects/Webserver/Lib/HTTPServerApp.c
new file mode 100644
index 000000000..01aab76ea
--- /dev/null
+++ b/Projects/Webserver/Lib/HTTPServerApp.c
@@ -0,0 +1,177 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Simple HTTP Webserver Application. When connected to the uIP stack,
+ * this will serve out files to HTTP clients.
+ */
+
+#include "HTTPServerApp.h"
+
+/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
+ * given location, and gives extra connection information.
+ */
+char PROGMEM HTTP200Header[] = "HTTP/1.1 200 OK\r\n"
+ "Server: LUFA RNDIS\r\n"
+ "Content-type: text/html\r\n"
+ "Connection: close\r\n\r\n";
+
+/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given
+ * given URL is invalid, and gives extra error information.
+ */
+char PROGMEM HTTP404Header[] = "HTTP/1.1 404 Not Found\r\n"
+ "Server: LUFA RNDIS\r\n"
+ "Connection: close\r\n\r\n"
+ "The requested file was not found.";
+
+/** FAT Fs structure to hold the internal state of the FAT driver for the dataflash contents. */
+FATFS DiskFATState;
+
+/** Initialization function for the simple HTTP webserver. */
+void WebserverApp_Init(void)
+{
+ /* Listen on port 80 for HTTP connections from hosts */
+ uip_listen(HTONS(HTTP_SERVER_PORT));
+
+ /* Mount the dataflash disk via FatFS */
+ f_mount(0, &DiskFATState);
+}
+
+/** uIP stack application callback for the simple HTTP webserver. This function must be called each time the
+ * TCP/IP stack needs a TCP packet to be processed.
+ */
+void WebserverApp_Callback(void)
+{
+ uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
+ char* AppData = (char*)uip_appdata;
+ uint16_t AppDataSize = 0;
+
+ if (uip_aborted() || uip_timedout())
+ {
+ /* Close the file before terminating, if it is open */
+ f_close(&AppState->FileToSend);
+
+ AppState->CurrentState = WEBSERVER_STATE_Closed;
+
+ return;
+ }
+ else if (uip_closed())
+ {
+ /* Completed connection, just return */
+ return;
+ }
+ else if (uip_connected())
+ {
+ /* New connection - initialize connection state and data pointer to the appropriate HTTP header */
+ AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;
+ }
+
+ switch (AppState->CurrentState)
+ {
+ case WEBSERVER_STATE_OpenRequestedFile:
+ /* Wait for the packet containing the request header */
+ if (uip_datalen())
+ {
+ /* Must be a GET request, abort otherwise */
+ if (strncmp(AppData, "GET ", (sizeof("GET ") - 1)) != 0)
+ {
+ uip_abort();
+ break;
+ }
+
+ char FileName[13];
+
+ /* Copy over the requested filename from the GET request */
+ for (uint8_t i = 0; i < (sizeof(FileName) - 1); i++)
+ {
+ FileName[i] = AppData[sizeof("GET ") + i];
+
+ if (FileName[i] == ' ')
+ {
+ FileName[i] = 0x00;
+ break;
+ }
+ }
+
+ /* Ensure requested filename is null-terminated */
+ FileName[(sizeof(FileName) - 1)] = 0x00;
+
+ /* If no filename specified, assume the default of INDEX.HTM */
+ if (FileName[0] == 0x00)
+ strcpy(FileName, "INDEX.HTM");
+
+ /* Try to open the file from the Dataflash disk */
+ AppState->FileOpen = (f_open(&AppState->FileToSend, FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);
+
+ AppState->CurrentState = WEBSERVER_STATE_SendHeaders;
+ }
+
+ break;
+ case WEBSERVER_STATE_SendHeaders:
+ /* Determine what HTTP header should be sent to the client */
+ if (AppState->FileOpen)
+ {
+ AppDataSize = strlen_P(HTTP200Header);
+ strncpy_P(AppData, HTTP200Header, AppDataSize);
+ }
+ else
+ {
+ AppDataSize = strlen_P(HTTP404Header);
+ strncpy_P(AppData, HTTP404Header, AppDataSize);
+ }
+
+ uip_send(AppData, AppDataSize);
+
+ AppState->CurrentState = WEBSERVER_STATE_SendData;
+ break;
+ case WEBSERVER_STATE_SendData:
+ /* If end of file/file not open, progress to the close state */
+ if (!(AppState->FileOpen))
+ {
+ f_close(&AppState->FileToSend);
+ uip_close();
+ AppState->CurrentState = WEBSERVER_STATE_Closed;
+ break;
+ }
+
+ uint16_t MaxSegSize = uip_mss();
+
+ /* Read the next chunk of data from the open file */
+ f_read(&AppState->FileToSend, AppData, MaxSegSize, &AppDataSize);
+ AppState->FileOpen = (MaxSegSize == AppDataSize);
+
+ /* If data was read, send it to the client */
+ if (AppDataSize)
+ uip_send(AppData, AppDataSize);
+
+ break;
+ }
+}
diff --git a/Projects/Webserver/Lib/WebserverApp.h b/Projects/Webserver/Lib/HTTPServerApp.h
index c788bdbeb..b96e2e303 100644
--- a/Projects/Webserver/Lib/WebserverApp.h
+++ b/Projects/Webserver/Lib/HTTPServerApp.h
@@ -30,24 +30,26 @@
/** \file
*
- * Header file for WebserverApp.c.
+ * Header file for HTTPServerApp.c.
*/
-#ifndef _WEBSERVER_APP_H_
-#define _WEBSERVER_APP_H_
+#ifndef _HTTPSERVER_APP_H_
+#define _HTTPSERVER_APP_H_
/* Includes: */
- #include <stdio.h>
#include <avr/pgmspace.h>
+ #include <string.h>
#include <LUFA/Version.h>
#include <uip.h>
+ #include <ff.h>
/* Enums: */
/** States for each HTTP connection to the webserver. */
enum Webserver_States_t
{
+ WEBSERVER_STATE_OpenRequestedFile, /** Currently opening requested file */
WEBSERVER_STATE_SendHeaders, /**< Currently sending HTTP headers to the client */
WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */
WEBSERVER_STATE_Closed, /**< Connection closed after all data sent */
diff --git a/Projects/Webserver/Lib/SCSI.c b/Projects/Webserver/Lib/SCSI.c
new file mode 100644
index 000000000..933253b46
--- /dev/null
+++ b/Projects/Webserver/Lib/SCSI.c
@@ -0,0 +1,281 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * SCSI command processing routines, for SCSI commands issued by the host. Mass Storage
+ * devices use a thin "Bulk-Only Transport" protocol for issuing commands and status information,
+ * which wrap around standard SCSI device commands for controlling the actual storage medium.
+ */
+
+#define INCLUDE_FROM_SCSI_C
+#include "SCSI.h"
+
+/** Structure to hold the SCSI response data to a SCSI INQUIRY command. This gives information about the device's
+ * features and capabilities.
+ */
+SCSI_Inquiry_Response_t InquiryData =
+ {
+ .DeviceType = DEVICE_TYPE_BLOCK,
+ .PeripheralQualifier = 0,
+
+ .Removable = true,
+
+ .Version = 0,
+
+ .ResponseDataFormat = 2,
+ .NormACA = false,
+ .TrmTsk = false,
+ .AERC = false,
+
+ .AdditionalLength = 0x1F,
+
+ .SoftReset = false,
+ .CmdQue = false,
+ .Linked = false,
+ .Sync = false,
+ .WideBus16Bit = false,
+ .WideBus32Bit = false,
+ .RelAddr = false,
+
+ .VendorID = "LUFA",
+ .ProductID = "Dataflash Disk",
+ .RevisionID = {'0','.','0','0'},
+ };
+
+/** Structure to hold the sense data for the last issued SCSI command, which is returned to the host after a SCSI REQUEST SENSE
+ * command is issued. This gives information on exactly why the last command failed to complete.
+ */
+SCSI_Request_Sense_Response_t SenseData =
+ {
+ .ResponseCode = 0x70,
+ .AdditionalLength = 0x0A,
+ };
+
+
+/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches
+ * to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns
+ * a command failure due to a ILLEGAL REQUEST.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ */
+bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ /* Set initial sense data, before the requested command is processed */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
+ SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+
+ /* Run the appropriate SCSI command hander function based on the passed command */
+ switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0])
+ {
+ case SCSI_CMD_INQUIRY:
+ SCSI_Command_Inquiry(MSInterfaceInfo);
+ break;
+ case SCSI_CMD_REQUEST_SENSE:
+ SCSI_Command_Request_Sense(MSInterfaceInfo);
+ break;
+ case SCSI_CMD_READ_CAPACITY_10:
+ SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
+ break;
+ case SCSI_CMD_SEND_DIAGNOSTIC:
+ SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
+ break;
+ case SCSI_CMD_WRITE_10:
+ SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
+ break;
+ case SCSI_CMD_READ_10:
+ SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
+ break;
+ case SCSI_CMD_TEST_UNIT_READY:
+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ case SCSI_CMD_VERIFY_10:
+ /* These commands should just succeed, no handling required */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
+ break;
+ default:
+ /* Update the SENSE key to reflect the invalid command */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_COMMAND,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+ break;
+ }
+
+ return (SenseData.SenseKey == SCSI_SENSE_KEY_GOOD);
+}
+
+/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
+ * and capabilities to the host.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ */
+static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 8) |
+ MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]);
+ uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength :
+ sizeof(InquiryData);
+
+ /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
+ if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
+ MSInterfaceInfo->State.CommandBlock.SCSICommandData[2])
+ {
+ /* Optional but unsupported bits set - update the SENSE key and fail the request */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+
+ return;
+ }
+
+ Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK);
+
+ uint8_t PadBytes[AllocationLength - BytesTransferred];
+
+ /* Pad out remaining bytes with 0x00 */
+ Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
+
+ /* Finalize the stream transfer to send the last packet */
+ Endpoint_ClearIN();
+
+ /* Succeed the command and update the bytes transferred counter */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
+}
+
+/** Command processing for an issued SCSI REQUEST SENSE command. This command returns information about the last issued command,
+ * including the error code and additional error information so that the host can determine why a command failed to complete.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ */
+static void SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
+ uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
+
+ uint8_t PadBytes[AllocationLength - BytesTransferred];
+
+ Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
+ Endpoint_ClearIN();
+
+ /* Succeed the command and update the bytes transferred counter */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
+}
+
+/** Command processing for an issued SCSI READ CAPACITY (10) command. This command returns information about the device's capacity
+ * on the selected Logical Unit (drive), as a number of OS-sized blocks.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ */
+static void SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ uint32_t LastBlockAddressInLUN = (VIRTUAL_MEMORY_BLOCKS - 1);
+ uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
+
+ Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
+ Endpoint_ClearIN();
+
+ /* Succeed the command and update the bytes transferred counter */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 8;
+}
+
+/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the
+ * board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is
+ * supported.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ */
+static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ /* Check to see if the SELF TEST bit is not set */
+ if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2)))
+ {
+ /* Only self-test supported - update SENSE key and fail the command */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+
+ return;
+ }
+
+ /* Check to see if all attached Dataflash ICs are functional */
+ if (!(DataflashManager_CheckDataflashOperation()))
+ {
+ /* Update SENSE key with a hardware error condition and return command fail */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR,
+ SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+
+ return;
+ }
+
+ /* Succeed the command and update the bytes transferred counter */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
+}
+
+/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
+ * and total number of blocks to process, then calls the appropriate low-level dataflash routine to handle the actual
+ * reading and writing of the data.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
+ * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
+ */
+static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead)
+{
+ uint32_t BlockAddress;
+ uint16_t TotalBlocks;
+
+ /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
+ BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
+
+ /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */
+ TotalBlocks = SwapEndian_16(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]);
+
+ /* Check if the block address is outside the maximum allowable value for the LUN */
+ if (BlockAddress >= VIRTUAL_MEMORY_BLOCKS)
+ {
+ /* Block address is invalid, update SENSE key and return command fail */
+ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+
+ return;
+ }
+
+ /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
+ if (IsDataRead == DATA_READ)
+ DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
+ else
+ DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
+
+ /* Update the bytes transferred counter and succeed the command */
+ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
+}
diff --git a/Projects/Webserver/Lib/SCSI.h b/Projects/Webserver/Lib/SCSI.h
new file mode 100644
index 000000000..aa7d9327c
--- /dev/null
+++ b/Projects/Webserver/Lib/SCSI.h
@@ -0,0 +1,85 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for SCSI.c.
+ */
+
+#ifndef _SCSI_H_
+#define _SCSI_H_
+
+ /* Includes: */
+ #include <avr/io.h>
+ #include <avr/pgmspace.h>
+
+ #include <LUFA/Drivers/USB/USB.h>
+ #include <LUFA/Drivers/USB/Class/MassStorage.h>
+
+ #include "../Descriptors.h"
+ #include "DataflashManager.h"
+
+ /* Macros: */
+ /** Macro to set the current SCSI sense data to the given key, additional sense code and additional sense qualifier. This
+ * is for convenience, as it allows for all three sense values (returned upon request to the host to give information about
+ * the last command failure) in a quick and easy manner.
+ *
+ * \param[in] key New SCSI sense key to set the sense code to
+ * \param[in] acode New SCSI additional sense key to set the additional sense code to
+ * \param[in] aqual New SCSI additional sense key qualifier to set the additional sense qualifier code to
+ */
+ #define SCSI_SET_SENSE(key, acode, aqual) MACROS{ SenseData.SenseKey = (key); \
+ SenseData.AdditionalSenseCode = (acode); \
+ SenseData.AdditionalSenseQualifier = (aqual); }MACROE
+
+ /** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
+ #define DATA_READ true
+
+ /** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
+ #define DATA_WRITE false
+
+ /** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */
+ #define DEVICE_TYPE_BLOCK 0x00
+
+ /** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
+ #define DEVICE_TYPE_CDROM 0x05
+
+ /* Function Prototypes: */
+ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+
+ #if defined(INCLUDE_FROM_SCSI_C)
+ static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+ static void SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+ static void SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+ static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+ static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead);
+ #endif
+
+#endif
diff --git a/Projects/Webserver/Lib/WebserverApp.c b/Projects/Webserver/Lib/WebserverApp.c
deleted file mode 100644
index 02f38be87..000000000
--- a/Projects/Webserver/Lib/WebserverApp.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 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 disclaim 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
- *
- * Simple HTTP Webserver Application. When connected to the uIP stack,
- * this will serve out files to HTTP clients.
- */
-
-#include "WebserverApp.h"
-
-/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
- * given location, and gives extra connection information.
- */
-char PROGMEM HTTP200Header[] = "HTTP/1.1 200 OK\r\n"
- "Server: LUFA RNDIS\r\n"
- "Content-type: text/html\r\n"
- "Connection: close\r\n\r\n";
-
-/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given
- * given URL is invalid, and gives extra error information.
- */
-char PROGMEM HTTP404Header[] = "HTTP/1.1 404 Not Found\r\n"
- "Server: LUFA RNDIS\r\n"
- "Connection: close\r\n\r\n";
-
-/** Static HTTP page to serve to the host when a HTTP request is made from a host. */
-char PROGMEM HTTPPage[] =
- "<html>"
- " <head>"
- " <title>"
- " LUFA Webserver Demo"
- " </title>"
- " </head>"
- " <body>"
- " <h1>Hello from your USB AVR!</h1>"
- " <p>"
- " Hello! Welcome to the LUFA RNDIS Demo Webserver test page, running on your USB AVR via the LUFA library and uIP TCP/IP network stack. This"
- " demonstrates a simple HTTP webserver serving out pages to HTTP clients."
- " <br /><br />"
- " <small>Project Information: <a href=\"http://www.fourwalledcubicle.com/LUFA.php\">http://www.fourwalledcubicle.com/LUFA.php</a>.</small>"
- " <hr />"
- " <i>LUFA Version: </i>" LUFA_VERSION_STRING
- " </p>"
- " </body>"
- "</html>";
-
-/** Initialization function for the simple HTTP webserver. */
-void WebserverApp_Init(void)
-{
- /* Listen on port 80 for HTTP connections from hosts */
- uip_listen(HTONS(HTTP_SERVER_PORT));
-}
-
-/** uIP stack application callback for the simple HTTP webserver. This function must be called each time the
- * TCP/IP stack needs a TCP packet to be processed.
- */
-void WebserverApp_Callback(void)
-{
- uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
- char* AppData = (char*)uip_appdata;
- uint16_t AppDataSize = 0;
-
- if (uip_closed() || uip_aborted() || uip_timedout())
- {
- /* Terminated or completed connection - don't send any new data */
- return;
- }
- else if (uip_connected())
- {
- /* New connection - initialize connection state and data pointer to the appropriate HTTP header */
- AppState->SendPos = HTTP200Header;
- AppState->CurrentState = WEBSERVER_STATE_SendHeaders;
- }
-
- /* Calculate the maximum segment size and remaining data size */
- uint16_t BytesRemaining = strlen_P(AppState->SendPos);
- uint16_t MaxSegSize = uip_mss();
-
- /* No more bytes remaining in the current data being sent - progress to next data chunk or
- * terminate the connection once all chunks are sent */
- if (!(BytesRemaining))
- {
- /* Check which data chunk we are currently sending (header or data) */
- if (AppState->CurrentState == WEBSERVER_STATE_SendHeaders)
- {
- AppState->SendPos = HTTPPage;
- AppState->CurrentState = WEBSERVER_STATE_SendData;
- }
- else if (AppState->CurrentState == WEBSERVER_STATE_SendData)
- {
- uip_close();
- AppState->CurrentState = WEBSERVER_STATE_Closed;
- }
-
- return;
- }
- else if (BytesRemaining > MaxSegSize)
- {
- /* More bytes remaining to send than the maximum segment size, send next chunk */
- AppDataSize = MaxSegSize;
- }
- else
- {
- /* Less bytes than the segment size remaining, send all remaining bytes in the one packet */
- AppDataSize = BytesRemaining;
- }
-
- /* Copy over the next data segment to the application buffer, advance send position pointer */
- strncpy_P(AppData, AppState->SendPos, AppDataSize);
- AppState->SendPos += AppDataSize;
-
- /* Send the data to the requesting host */
- uip_send(AppData, AppDataSize);
-}
diff --git a/Projects/Webserver/Lib/uIPManagement.c b/Projects/Webserver/Lib/uIPManagement.c
new file mode 100644
index 000000000..dd9f15f42
--- /dev/null
+++ b/Projects/Webserver/Lib/uIPManagement.c
@@ -0,0 +1,189 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * uIP Managament functions. This file contains the functions and globals needed to maintain the uIP
+ * stack once an RNDIS device has been attached to the system.
+ */
+
+#define INCLUDE_FROM_UIPMANAGEMENT_C
+#include "uIPManagement.h"
+
+/** Connection timer, to retain the time elapsed since the last time the uIP connections were managed. */
+struct timer ConnectionTimer;
+
+/** ARP timer, to retain the time elapsed since the ARP cache was last updated. */
+struct timer ARPTimer;
+
+/** MAC address of the RNDIS device, when enumerated */
+struct uip_eth_addr MACAddress;
+
+
+/** Configures the uIP stack ready for network traffic. */
+void uIPManagement_Init(void)
+{
+ /* uIP Timing Initialization */
+ clock_init();
+ timer_set(&ConnectionTimer, CLOCK_SECOND / 2);
+ timer_set(&ARPTimer, CLOCK_SECOND * 10);
+
+ /* uIP Stack Initialization */
+ uip_init();
+
+ /* DHCP/Server IP Settings Initialization */
+ #if defined(ENABLE_DHCP)
+ DHCPApp_Init();
+ #else
+ uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
+ uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
+ uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
+ uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2], DEVICE_GATEWAY[3]);
+ uip_sethostaddr(&IPAddress);
+ uip_setnetmask(&Netmask);
+ uip_setdraddr(&GatewayIPAddress);
+ #endif
+
+ uip_setethaddr(MACAddress);
+
+ /* HTTP Webserver Initialization */
+ WebserverApp_Init();
+}
+
+/** uIP Management function. This function manages the uIP stack when called while an RNDIS device has been
+ * attached to the system.
+ */
+void uIPManagement_ManageNetwork(void)
+{
+ if ((USB_CurrentMode == USB_MODE_HOST) && (USB_HostState == HOST_STATE_Configured))
+ {
+ uIPManagement_ProcessIncommingPacket();
+ uIPManagement_ManageConnections();
+ }
+}
+
+/** Processes incomming packets to the server from the connected RNDIS device, creating responses as needed. */
+static void uIPManagement_ProcessIncommingPacket(void)
+{
+ if (RNDIS_Host_IsPacketReceived(&Ethernet_RNDIS_Interface))
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
+
+ /* Read the incomming packet straight into the UIP packet buffer */
+ RNDIS_Host_ReadPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], &uip_len);
+
+ if (uip_len > 0)
+ {
+ bool PacketHandled = true;
+
+ struct uip_eth_hdr* EthernetHeader = (struct uip_eth_hdr*)&uip_buf[0];
+ if (EthernetHeader->type == HTONS(UIP_ETHTYPE_IP))
+ {
+ /* Filter packet by MAC destination */
+ uip_arp_ipin();
+
+ /* Process incomming packet */
+ uip_input();
+
+ /* Add destination MAC to outgoing packet */
+ if (uip_len > 0)
+ uip_arp_out();
+ }
+ else if (EthernetHeader->type == HTONS(UIP_ETHTYPE_ARP))
+ {
+ /* Process ARP packet */
+ uip_arp_arpin();
+ }
+ else
+ {
+ PacketHandled = false;
+ }
+
+ /* If a response was generated, send it */
+ if ((uip_len > 0) && PacketHandled)
+ RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
+ }
+
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+ }
+}
+
+/** Manages the currently open network connections, including TCP and (if enabled) UDP. */
+static void uIPManagement_ManageConnections(void)
+{
+ /* Manage open connections */
+ if (timer_expired(&ConnectionTimer))
+ {
+ timer_reset(&ConnectionTimer);
+
+ LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
+
+ for (uint8_t i = 0; i < UIP_CONNS; i++)
+ {
+ /* Run periodic connection management for each TCP connection */
+ uip_periodic(i);
+
+ /* If a response was generated, send it */
+ if (uip_len > 0)
+ {
+ /* Add destination MAC to outgoing packet */
+ uip_arp_out();
+
+ RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
+ }
+ }
+
+ #if defined(ENABLE_DHCP)
+ for (uint8_t i = 0; i < UIP_UDP_CONNS; i++)
+ {
+ /* Run periodic connection management for each UDP connection */
+ uip_udp_periodic(i);
+
+ /* If a response was generated, send it */
+ if (uip_len > 0)
+ {
+ /* Add destination MAC to outgoing packet */
+ uip_arp_out();
+
+ RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
+ }
+ }
+ #endif
+
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+ }
+
+ /* Manage ARP cache refreshing */
+ if (timer_expired(&ARPTimer))
+ {
+ timer_reset(&ARPTimer);
+ uip_arp_timer();
+ }
+}
diff --git a/Projects/Webserver/Lib/uIPManagement.h b/Projects/Webserver/Lib/uIPManagement.h
new file mode 100644
index 000000000..24881556b
--- /dev/null
+++ b/Projects/Webserver/Lib/uIPManagement.h
@@ -0,0 +1,73 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for uIPManagement.c.
+ */
+
+#ifndef _UIPMANAGEMENT_H_
+#define _UIPMANAGEMENT_H_
+
+ /* Includes: */
+ #include <LUFA/Drivers/USB/Class/RNDIS.h>
+
+ #include <uip.h>
+ #include <uip_arp.h>
+ #include <timer.h>
+
+ #include "Lib/DHCPApp.h"
+ #include "Lib/HTTPServerApp.h"
+
+ /* Macros: */
+ /** IP address that the webserver should use once connected to a RNDIS device (when DHCP is disabled). */
+ #define DEVICE_IP_ADDRESS (uint8_t[]){192, 168, 1, 10}
+
+ /** Netmask that the webserver should once connected to a RNDIS device (when DHCP is disabled). */
+ #define DEVICE_NETMASK (uint8_t[]){255, 255, 255, 0}
+
+ /** IP address of the default gateway the webserver should use when routing outside the local subnet
+ * (when DHCP is disabled).
+ */
+ #define DEVICE_GATEWAY (uint8_t[]){192, 168, 1, 1}
+
+ /* External Variables: */
+ extern struct uip_eth_addr MACAddress;
+
+ /* Function Prototypes: */
+ void uIPManagement_Init(void);
+ void uIPManagement_ManageNetwork(void);
+
+ #if defined(INCLUDE_FROM_UIPMANAGEMENT_C)
+ static void uIPManagement_ProcessIncommingPacket(void);
+ static void uIPManagement_ManageConnections(void);
+ #endif
+
+#endif
diff --git a/Projects/Webserver/Lib/uip/conf/apps-conf.h b/Projects/Webserver/Lib/uip/conf/apps-conf.h
index fc9727dcd..76cd93719 100644
--- a/Projects/Webserver/Lib/uip/conf/apps-conf.h
+++ b/Projects/Webserver/Lib/uip/conf/apps-conf.h
@@ -1,10 +1,13 @@
#ifndef __APPS_CONF_H__
#define __APPS_CONF_H__
+ #include <ff.h>
+
typedef struct
{
uint8_t CurrentState;
- char* SendPos;
+ FIL FileToSend;
+ bool FileOpen;
} uip_tcp_appstate_t;
typedef struct
diff --git a/Projects/Webserver/USBDeviceMode.c b/Projects/Webserver/USBDeviceMode.c
new file mode 100644
index 000000000..c93ba4632
--- /dev/null
+++ b/Projects/Webserver/USBDeviceMode.c
@@ -0,0 +1,113 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * USB Device Mode management functions and variables. This file contains the LUFA code required to
+ * manage the USB Mass Storage device mode.
+ */
+
+#include "USBDeviceMode.h"
+
+/** LUFA Mass Storage Class driver interface configuration and state information. This structure is
+ * passed to all Mass Storage Class driver functions, so that multiple instances of the same class
+ * within a device can be differentiated from one another.
+ */
+USB_ClassInfo_MS_Device_t Disk_MS_Interface =
+ {
+ .Config =
+ {
+ .InterfaceNumber = 0,
+
+ .DataINEndpointNumber = MASS_STORAGE_IN_EPNUM,
+ .DataINEndpointSize = MASS_STORAGE_IO_EPSIZE,
+ .DataINEndpointDoubleBank = false,
+
+ .DataOUTEndpointNumber = MASS_STORAGE_OUT_EPNUM,
+ .DataOUTEndpointSize = MASS_STORAGE_IO_EPSIZE,
+ .DataOUTEndpointDoubleBank = false,
+
+ .TotalLUNs = 1,
+ },
+ };
+
+
+/** USB device mode management task. This function manages the Mass Storage Device class driver when the device is
+ * initialized in USB device mode.
+ */
+void USBDeviceMode_USBTask(void)
+{
+ if (USB_CurrentMode != USB_MODE_DEVICE)
+ return;
+
+ MS_Device_USBTask(&Disk_MS_Interface);
+}
+
+/** Event handler for the library USB Connection event. */
+void EVENT_USB_Device_Connect(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
+}
+
+/** Event handler for the library USB Disconnection event. */
+void EVENT_USB_Device_Disconnect(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+}
+
+/** Event handler for the library USB Configuration Changed event. */
+void EVENT_USB_Device_ConfigurationChanged(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+
+ if (!(MS_Device_ConfigureEndpoints(&Disk_MS_Interface)))
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+}
+
+/** Event handler for the library USB Unhandled Control Request event. */
+void EVENT_USB_Device_UnhandledControlRequest(void)
+{
+ MS_Device_ProcessControlRequest(&Disk_MS_Interface);
+}
+
+/** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed.
+ *
+ * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface configuration structure being referenced
+ */
+bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
+{
+ bool CommandSuccess;
+
+ LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
+ CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+
+ return CommandSuccess;
+}
diff --git a/Projects/Webserver/USBDeviceMode.h b/Projects/Webserver/USBDeviceMode.h
new file mode 100644
index 000000000..d76c66778
--- /dev/null
+++ b/Projects/Webserver/USBDeviceMode.h
@@ -0,0 +1,56 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for USBDeviceMode.c.
+ */
+
+#ifndef _USBDEVICEMODE_H_
+#define _USBDEVICEMODE_H_
+
+ /* Includes: */
+ #include <LUFA/Drivers/USB/Class/MassStorage.h>
+
+ #include "Webserver.h"
+ #include "Descriptors.h"
+ #include "Lib/SCSI.h"
+
+ /* Function Prototypes: */
+ void USBDeviceMode_USBTask(void);
+
+ void EVENT_USB_Device_Connect(void);
+ void EVENT_USB_Device_Disconnect(void);
+ void EVENT_USB_Device_ConfigurationChanged(void);
+ void EVENT_USB_Device_UnhandledControlRequest(void);
+
+ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
+
+#endif
diff --git a/Projects/Webserver/USBHostMode.c b/Projects/Webserver/USBHostMode.c
new file mode 100644
index 000000000..14f33e07c
--- /dev/null
+++ b/Projects/Webserver/USBHostMode.c
@@ -0,0 +1,178 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * USB Host Mode management functions and variables. This file contains the LUFA code required to
+ * manage the USB RNDIS host mode.
+ */
+
+#include "USBHostMode.h"
+
+/** LUFA RNDIS Class driver interface configuration and state information. This structure is
+ * passed to all RNDIS Class driver functions, so that multiple instances of the same class
+ * within a device can be differentiated from one another.
+ */
+USB_ClassInfo_RNDIS_Host_t Ethernet_RNDIS_Interface =
+ {
+ .Config =
+ {
+ .DataINPipeNumber = 1,
+ .DataINPipeDoubleBank = false,
+
+ .DataOUTPipeNumber = 2,
+ .DataOUTPipeDoubleBank = false,
+
+ .NotificationPipeNumber = 3,
+ .NotificationPipeDoubleBank = false,
+
+ .HostMaxPacketSize = UIP_CONF_BUFFER_SIZE,
+ },
+ };
+
+
+/** USB host mode management task. This function manages the RNDIS Host class driver and uIP stack when the device is
+ * initialized in USB host mode.
+ */
+void USBHostMode_USBTask(void)
+{
+ if (USB_CurrentMode != USB_MODE_HOST)
+ return;
+
+ switch (USB_HostState)
+ {
+ case HOST_STATE_Addressed:
+ LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
+
+ uint16_t ConfigDescriptorSize;
+ uint8_t ConfigDescriptorData[512];
+
+ if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
+ sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ if (RNDIS_Host_ConfigurePipes(&Ethernet_RNDIS_Interface,
+ ConfigDescriptorSize, ConfigDescriptorData) != RNDIS_ENUMERROR_NoError)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ if (RNDIS_Host_InitializeDevice(&Ethernet_RNDIS_Interface) != HOST_SENDCONTROL_Successful)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ uint32_t PacketFilter = (REMOTE_NDIS_PACKET_DIRECTED | REMOTE_NDIS_PACKET_BROADCAST);
+ if (RNDIS_Host_SetRNDISProperty(&Ethernet_RNDIS_Interface, OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter, sizeof(PacketFilter)) != HOST_SENDCONTROL_Successful)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ if (RNDIS_Host_QueryRNDISProperty(&Ethernet_RNDIS_Interface, OID_802_3_CURRENT_ADDRESS,
+ &MACAddress, sizeof(MACAddress)) != HOST_SENDCONTROL_Successful)
+ {
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+ break;
+ }
+
+ /* Initialize uIP stack */
+ uIPManagement_Init();
+
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+ USB_HostState = HOST_STATE_Configured;
+ break;
+ case HOST_STATE_Configured:
+ uIPManagement_ManageNetwork();
+
+ break;
+ }
+
+ RNDIS_Host_USBTask(&Ethernet_RNDIS_Interface);
+}
+
+/** Event handler for the USB_DeviceAttached event. This indicates that a device has been attached to the host, and
+ * starts the library USB task to begin the enumeration and USB management process.
+ */
+void EVENT_USB_Host_DeviceAttached(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
+}
+
+/** Event handler for the USB_DeviceUnattached event. This indicates that a device has been removed from the host, and
+ * stops the library USB task management process.
+ */
+void EVENT_USB_Host_DeviceUnattached(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+}
+
+/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully
+ * enumerated by the host and is now ready to be used by the application.
+ */
+void EVENT_USB_Host_DeviceEnumerationComplete(void)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_READY);
+}
+
+/** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */
+void EVENT_USB_Host_HostError(const uint8_t ErrorCode)
+{
+ USB_ShutDown();
+
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ for(;;);
+}
+
+/** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while
+ * enumerating an attached USB device.
+ */
+void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode)
+{
+ LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+}
diff --git a/Projects/Webserver/USBHostMode.h b/Projects/Webserver/USBHostMode.h
new file mode 100644
index 000000000..03387edd2
--- /dev/null
+++ b/Projects/Webserver/USBHostMode.h
@@ -0,0 +1,57 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.fourwalledcubicle.com
+*/
+
+/*
+ Copyright 2010 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 disclaim 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
+ *
+ * Header file for USBHostMode.c.
+ */
+
+#ifndef _USBHOSTMODE_H_
+#define _USBHOSTMODE_H_
+
+ /* Includes: */
+ #include <LUFA/Drivers/USB/Class/RNDIS.h>
+
+ #include "Webserver.h"
+ #include "Lib/uIPManagement.h"
+
+ /* External Variables: */
+ extern USB_ClassInfo_RNDIS_Host_t Ethernet_RNDIS_Interface;
+
+ /* Function Prototypes: */
+ void USBHostMode_USBTask(void);
+
+ void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
+ void EVENT_USB_Host_DeviceAttached(void);
+ void EVENT_USB_Host_DeviceUnattached(void);
+ void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode);
+ void EVENT_USB_Host_DeviceEnumerationComplete(void);
+
+#endif
diff --git a/Projects/Webserver/Webserver.c b/Projects/Webserver/Webserver.c
index ec1dabffb..47fd9c7e5 100644
--- a/Projects/Webserver/Webserver.c
+++ b/Projects/Webserver/Webserver.c
@@ -36,36 +36,6 @@
#include "Webserver.h"
-/** LUFA RNDIS Class driver interface configuration and state information. This structure is
- * passed to all RNDIS Class driver functions, so that multiple instances of the same class
- * within a device can be differentiated from one another.
- */
-USB_ClassInfo_RNDIS_Host_t Ethernet_RNDIS_Interface =
- {
- .Config =
- {
- .DataINPipeNumber = 1,
- .DataINPipeDoubleBank = false,
-
- .DataOUTPipeNumber = 2,
- .DataOUTPipeDoubleBank = false,
-
- .NotificationPipeNumber = 3,
- .NotificationPipeDoubleBank = false,
-
- .HostMaxPacketSize = UIP_CONF_BUFFER_SIZE,
- },
- };
-
-/** Connection timer, to retain the time elapsed since the last time the uIP connections were managed. */
-struct timer ConnectionTimer;
-
-/** ARP timer, to retain the time elapsed since the ARP cache was last updated. */
-struct timer ARPTimer;
-
-/** MAC address of the RNDIS device, when enumerated */
-struct uip_eth_addr MACAddress;
-
/** Main program entry point. This routine configures the hardware required by the application, then
* enters a loop to run the application tasks in sequence.
*/
@@ -77,177 +47,13 @@ int main(void)
for (;;)
{
- switch (USB_HostState)
- {
- case HOST_STATE_Addressed:
- LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
-
- uint16_t ConfigDescriptorSize;
- uint8_t ConfigDescriptorData[512];
+ USBDeviceMode_USBTask();
+ USBHostMode_USBTask();
- if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
- sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- if (RNDIS_Host_ConfigurePipes(&Ethernet_RNDIS_Interface,
- ConfigDescriptorSize, ConfigDescriptorData) != RNDIS_ENUMERROR_NoError)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- if (RNDIS_Host_InitializeDevice(&Ethernet_RNDIS_Interface) != HOST_SENDCONTROL_Successful)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- uint32_t PacketFilter = (REMOTE_NDIS_PACKET_DIRECTED | REMOTE_NDIS_PACKET_BROADCAST);
- if (RNDIS_Host_SetRNDISProperty(&Ethernet_RNDIS_Interface, OID_GEN_CURRENT_PACKET_FILTER,
- &PacketFilter, sizeof(PacketFilter)) != HOST_SENDCONTROL_Successful)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- if (RNDIS_Host_QueryRNDISProperty(&Ethernet_RNDIS_Interface, OID_802_3_CURRENT_ADDRESS,
- &MACAddress, sizeof(MACAddress)) != HOST_SENDCONTROL_Successful)
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- USB_HostState = HOST_STATE_WaitForDeviceRemoval;
- break;
- }
-
- uip_setethaddr(MACAddress);
-
- LEDs_SetAllLEDs(LEDMASK_USB_READY);
- USB_HostState = HOST_STATE_Configured;
- break;
- case HOST_STATE_Configured:
- ProcessIncommingPacket();
- ManageConnections();
-
- break;
- }
-
- RNDIS_Host_USBTask(&Ethernet_RNDIS_Interface);
USB_USBTask();
}
}
-/** Processes incomming packets to the server from the connected RNDIS device, creating responses as needed. */
-void ProcessIncommingPacket(void)
-{
- if (RNDIS_Host_IsPacketReceived(&Ethernet_RNDIS_Interface))
- {
- LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
-
- /* Read the incomming packet straight into the UIP packet buffer */
- RNDIS_Host_ReadPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], &uip_len);
-
- if (uip_len > 0)
- {
- bool PacketHandled = true;
-
- struct uip_eth_hdr* EthernetHeader = (struct uip_eth_hdr*)&uip_buf[0];
- if (EthernetHeader->type == HTONS(UIP_ETHTYPE_IP))
- {
- /* Filter packet by MAC destination */
- uip_arp_ipin();
-
- /* Process incomming packet */
- uip_input();
-
- /* Add destination MAC to outgoing packet */
- if (uip_len > 0)
- uip_arp_out();
- }
- else if (EthernetHeader->type == HTONS(UIP_ETHTYPE_ARP))
- {
- /* Process ARP packet */
- uip_arp_arpin();
- }
- else
- {
- PacketHandled = false;
- }
-
- /* If a response was generated, send it */
- if ((uip_len > 0) && PacketHandled)
- RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
- }
-
- LEDs_SetAllLEDs(LEDMASK_USB_READY);
- }
-}
-
-/** Manages the currently open network connections, including TCP and (if enabled) UDP. */
-void ManageConnections(void)
-{
- /* Manage open connections */
- if (timer_expired(&ConnectionTimer))
- {
- timer_reset(&ConnectionTimer);
-
- LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
-
- for (uint8_t i = 0; i < UIP_CONNS; i++)
- {
- /* Run periodic connection management for each TCP connection */
- uip_periodic(i);
-
- /* If a response was generated, send it */
- if (uip_len > 0)
- {
- /* Add destination MAC to outgoing packet */
- uip_arp_out();
-
- RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
- }
- }
-
- #if defined(ENABLE_DHCP)
- for (uint8_t i = 0; i < UIP_UDP_CONNS; i++)
- {
- /* Run periodic connection management for each UDP connection */
- uip_udp_periodic(i);
-
- /* If a response was generated, send it */
- if (uip_len > 0)
- {
- /* Add destination MAC to outgoing packet */
- uip_arp_out();
-
- RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
- }
- }
- #endif
-
- LEDs_SetAllLEDs(LEDMASK_USB_READY);
- }
-
- /* Manage ARP cache refreshing */
- if (timer_expired(&ARPTimer))
- {
- timer_reset(&ARPTimer);
- uip_arp_timer();
- }
-}
-
/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
@@ -259,71 +65,8 @@ void SetupHardware(void)
clock_prescale_set(clock_div_1);
/* Hardware Initialization */
+ SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_SCK_LEAD_FALLING | SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);
+ Dataflash_Init();
LEDs_Init();
- USB_Init();
-
- /* uIP Timing Initialization */
- clock_init();
- timer_set(&ConnectionTimer, CLOCK_SECOND / 2);
- timer_set(&ARPTimer, CLOCK_SECOND * 10);
-
- /* uIP Stack Initialization */
- uip_init();
-
- /* DHCP/Server IP Settings Initialization */
- #if defined(ENABLE_DHCP)
- DHCPApp_Init();
- #else
- uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
- uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
- uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
- uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2], DEVICE_GATEWAY[3]);
- uip_sethostaddr(&IPAddress);
- uip_setnetmask(&Netmask);
- uip_setdraddr(&GatewayIPAddress);
- #endif
-
- /* HTTP Webserver Initialization */
- WebserverApp_Init();
-}
-
-/** Event handler for the USB_DeviceAttached event. This indicates that a device has been attached to the host, and
- * starts the library USB task to begin the enumeration and USB management process.
- */
-void EVENT_USB_Host_DeviceAttached(void)
-{
- LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
-}
-
-/** Event handler for the USB_DeviceUnattached event. This indicates that a device has been removed from the host, and
- * stops the library USB task management process.
- */
-void EVENT_USB_Host_DeviceUnattached(void)
-{
- LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
-}
-
-/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully
- * enumerated by the host and is now ready to be used by the application.
- */
-void EVENT_USB_Host_DeviceEnumerationComplete(void)
-{
- LEDs_SetAllLEDs(LEDMASK_USB_READY);
-}
-
-/** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */
-void EVENT_USB_Host_HostError(const uint8_t ErrorCode)
-{
- USB_ShutDown();
-
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- for(;;);
-}
-
-/** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while
- * enumerating an attached USB device.
- */
-void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode)
-{
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+ USB_Init(USB_MODE_UID);
}
diff --git a/Projects/Webserver/Webserver.h b/Projects/Webserver/Webserver.h
index 13462a2a2..a9621e32f 100644
--- a/Projects/Webserver/Webserver.h
+++ b/Projects/Webserver/Webserver.h
@@ -44,28 +44,14 @@
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h>
+ #include <LUFA/Drivers/Board/Dataflash.h>
+ #include <LUFA/Drivers/Peripheral/SPI.h>
#include <LUFA/Drivers/USB/USB.h>
- #include <LUFA/Drivers/USB/Class/RNDIS.h>
- #include <uip.h>
- #include <uip_arp.h>
- #include <timer.h>
-
- #include "Lib/WebserverApp.h"
- #include "Lib/DHCPApp.h"
+ #include "USBDeviceMode.h"
+ #include "USBHostMode.h"
/* Macros: */
- /** IP address that the webserver should use once connected to a RNDIS device (when DHCP is disabled). */
- #define DEVICE_IP_ADDRESS (uint8_t[]){192, 168, 1, 10}
-
- /** Netmask that the webserver should once connected to a RNDIS device (when DHCP is disabled). */
- #define DEVICE_NETMASK (uint8_t[]){255, 255, 255, 0}
-
- /** IP address of the default gateway the webserver should use when routing outside the local subnet
- * (when DHCP is disabled).
- */
- #define DEVICE_GATEWAY (uint8_t[]){192, 168, 1, 1}
-
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
#define LEDMASK_USB_NOTREADY LEDS_LED1
@@ -80,19 +66,8 @@
/** LED mask for the library LED driver, to indicate that the USB interface is busy. */
#define LEDMASK_USB_BUSY LEDS_LED2
-
- /* External Variables: */
- extern struct uip_eth_addr MACAddress;
-
+
/* Function Prototypes: */
void SetupHardware(void);
- void ProcessIncommingPacket(void);
- void ManageConnections(void);
-
- void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
- void EVENT_USB_Host_DeviceAttached(void);
- void EVENT_USB_Host_DeviceUnattached(void);
- void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode);
- void EVENT_USB_Host_DeviceEnumerationComplete(void);
#endif
diff --git a/Projects/Webserver/Webserver.txt b/Projects/Webserver/Webserver.txt
index e1d298596..e78cf5eff 100644
--- a/Projects/Webserver/Webserver.txt
+++ b/Projects/Webserver/Webserver.txt
@@ -41,16 +41,22 @@
*
* \section SSec_Description Project Description:
*
- * Simple HTTP webserver project. This project combines the LUFA library with the uIP TCP/IP full network stack, to create a
- * RNDIS host capable of serving out HTTP webpages to up to 10 hosts simultaneously. This project demonstrates how the two
- * libraries can be combined into a robust network enabled application, with the addition of a RNDIS network device.
+ * Simple HTTP webserver project. This project combines the LUFA library with the uIP TCP/IP full network stack and FatFS
+ * library to create a RNDIS host capable of serving out HTTP webpages to multiple hosts simultaneously. This project
+ * demonstrates how the libraries can be combined into a robust network enabled application, with the addition of a RNDIS
+ * network device.
*
- * To use this project, plug the USB AVR into a RNDIS class device, such as a USB (desktop) modem. If compatible, the project
- * will enumerate the device, set the appropriate parameters needed for connectivity and begin listening for new HTTP connections
- * on port 80. The device IP, netmask and default gateway IP must be set to values appropriate for the RNDIS device being used
- * for this project to work.
+ * To use this project, plug the USB AVR into a computer, so that it enumerates as a standard Mass Storage device. Load
+ * HTML files onto the disk, so that they can be served out to clients -- the default file to serve should be called
+ * <i>index.htm<i>. Filenames must be in 8.3 format for them to be retrieved correctly by the webserver.
+
+ * When attached to a RNDIS class device, such as a USB (desktop) modem. If compatible, the system will enumerate the
+ * device, set the appropriate parameters needed for connectivity and begin listening for new HTTP connections on port 80.
+ * The device IP, netmask and default gateway IP must be set to values appropriate for the RNDIS device being used for this
+ * project to work, if the DHCP client is disabled (see \ref SSec_Options).
*
- * When properly configured, the webserver can be accessed from any HTTP webrowser by typing in the device's IP address.
+ * When properly configured, the webserver can be accessed from any HTTP webrowser by typing in the device's static or
+ * dynamically allocated IP address.
*
* \section SSec_Options Project Options
*
@@ -69,17 +75,17 @@
* </tr>
* <tr>
* <td>DEVICE_IP_ADDRESS</td>
- * <td>Webserver.h</td>
+ * <td>Lib/uIPManagement.h</td>
* <td>IP address that the webserver should use when connected to a RNDIS device (when ENABLE_DHCP is not defined).</td>
* </tr>
* <tr>
* <td>DEVICE_NETMASK</td>
- * <td>Webserver.h</td>
+ * <td>Lib/uIPManagement.h</td>
* <td>Netmask that the webserver should use when connected to a RNDIS device (when ENABLE_DHCP is not defined).</td>
* </tr>
* <tr>
* <td>DEVICE_GATEWAY</td>
- * <td>Webserver.h</td>
+ * <td>Lib/uIPManagement.h</td>
* <td>Default routing gateway that the webserver should use when connected to a RNDIS device (when ENABLE_DHCP
* is not defined).</td>
* </tr>
diff --git a/Projects/Webserver/makefile b/Projects/Webserver/makefile
index 4a1b85bdd..3c72ad875 100644
--- a/Projects/Webserver/makefile
+++ b/Projects/Webserver/makefile
@@ -116,14 +116,31 @@ LUFA_PATH = ../../
# LUFA library compile-time options
-LUFA_OPTS += -D USB_HOST_ONLY
-LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
+LUFA_OPTS = -D FIXED_CONTROL_ENDPOINT_SIZE=8
+LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
+LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
+LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
+ Descriptors.c \
+ USBDeviceMode.c \
+ USBHostMode.c \
+ Lib/SCSI.c \
+ Lib/uIPManagement.c \
Lib/DHCPApp.c \
- Lib/WebserverApp.c \
+ Lib/HTTPServerApp.c \
+ Lib/DataflashManager.c \
+ Lib/uip/uip.c \
+ Lib/uip/uip_arp.c \
+ Lib/uip/uiplib.c \
+ Lib/uip/psock.c \
+ Lib/uip/timer.c \
+ Lib/uip/uip-neighbor.c \
+ Lib/uip/conf/clock-arch.c \
+ Lib/FatFS/diskio.c \
+ Lib/FatFS/ff.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
@@ -134,17 +151,11 @@ SRC = $(TARGET).c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
+ $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/MassStorage.c \
+ $(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/MassStorage.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/RNDIS.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/RNDIS.c \
- Lib/uip/uip.c \
- Lib/uip/uip_arp.c \
- Lib/uip/uiplib.c \
- Lib/uip/psock.c \
- Lib/uip/timer.c \
- Lib/uip/uip-neighbor.c \
- Lib/uip/conf/clock-arch.c \
-
-
+
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
@@ -176,7 +187,7 @@ DEBUG = dwarf-2
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
-EXTRAINCDIRS = $(LUFA_PATH)/ Lib/uip/ Lib/uip/conf/
+EXTRAINCDIRS = $(LUFA_PATH)/ Lib/uip/ Lib/uip/conf/ Lib/FatFS/
# Compiler flag to set the C Standard level.