Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/thirdpin/pastilda.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthirdpin <n_lazareva@mail.ru>2016-07-19 18:52:24 +0300
committerthirdpin <n_lazareva@mail.ru>2016-07-19 18:52:24 +0300
commit6f994b871c9f673a4185a2fc6d824d8151d84359 (patch)
tree890356ed75c66576b274bbf925cfb2215bb6cd2a
parent26ba57fcb574c0ff313ff78210c2eed71a3b37b1 (diff)
Add lib openfat, SST25 driver, dummy file system
-rw-r--r--emb/pastilda/.cproject20
-rw-r--r--emb/pastilda/app/app.cpp56
-rw-r--r--emb/pastilda/app/app.h18
-rw-r--r--emb/pastilda/app/usb_dispatcher.cpp73
-rw-r--r--emb/pastilda/app/usb_dispatcher.h54
-rw-r--r--emb/pastilda/clock.h (renamed from emb/pastilda/hw/clock.h)0
-rw-r--r--emb/pastilda/flash/drv/SST25.cpp240
-rw-r--r--emb/pastilda/flash/drv/SST25.h125
-rw-r--r--emb/pastilda/flash/flash_memory.cpp218
-rw-r--r--emb/pastilda/flash/flash_memory.h102
-rw-r--r--emb/pastilda/hw/usb_device/ramdisk.c160
-rw-r--r--emb/pastilda/hw/usb_device/ramdisk.h14
-rw-r--r--emb/pastilda/keyboard.h (renamed from emb/pastilda/hw/keyboard.h)0
-rw-r--r--emb/pastilda/lib/libopenfat/bpb.h146
-rw-r--r--emb/pastilda/lib/libopenfat/direntry.c237
-rw-r--r--emb/pastilda/lib/libopenfat/direntry.h62
-rw-r--r--emb/pastilda/lib/libopenfat/fat_core.c231
-rw-r--r--emb/pastilda/lib/libopenfat/fat_core.h108
-rw-r--r--emb/pastilda/lib/libopenfat/mbr.c71
-rw-r--r--emb/pastilda/lib/libopenfat/openfat.h220
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/blockdev.h76
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/leaccess.h67
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/mbr.h64
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/unixlike.h47
-rw-r--r--emb/pastilda/lib/libopenfat/unixlike.c105
-rw-r--r--emb/pastilda/lib/libopenfat/write.c453
-rw-r--r--emb/pastilda/main.cpp9
-rw-r--r--emb/pastilda/stm32f405rg.ld (renamed from emb/pastilda/stm32f407vg.ld)0
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite.cpp (renamed from emb/pastilda/hw/usb_device/usbd_composite.cpp)25
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite.h (renamed from emb/pastilda/hw/usb_device/usbd_composite.h)28
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite_desc.cpp (renamed from emb/pastilda/hw/usb_device/usbd_composite_desc.cpp)2
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite_desc.h (renamed from emb/pastilda/hw/usb_device/usbd_composite_desc.h)0
-rw-r--r--emb/pastilda/usb/usb_host/usbh_host.cpp (renamed from emb/pastilda/hw/usb_host/usbh_host.cpp)2
-rw-r--r--emb/pastilda/usb/usb_host/usbh_host.h (renamed from emb/pastilda/hw/usb_host/usbh_host.h)0
34 files changed, 2672 insertions, 361 deletions
diff --git a/emb/pastilda/.cproject b/emb/pastilda/.cproject
index 4047913..5b58df7 100644
--- a/emb/pastilda/.cproject
+++ b/emb/pastilda/.cproject
@@ -56,11 +56,13 @@
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths.1095580488" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_device}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_host}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_device}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_host}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat/openfat}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
</option>
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.338584563" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
@@ -73,11 +75,15 @@
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths.1410012800" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/flash/drv}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/flash}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_device}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_host}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_device}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_host}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat/openfat}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
</option>
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.583307617" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
@@ -88,7 +94,7 @@
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.775878399" name="Cross ARM C++ Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker">
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections.631623800" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections" value="true" valueType="boolean"/>
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile.1994171085" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile" valueType="stringList">
- <listOptionValue builtIn="false" value="../stm32f407vg.ld"/>
+ <listOptionValue builtIn="false" value="../stm32f405rg.ld"/>
</option>
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart.933236374" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart" value="true" valueType="boolean"/>
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs.730199662" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs" valueType="libs">
diff --git a/emb/pastilda/app/app.cpp b/emb/pastilda/app/app.cpp
index 68192be..8ea95f3 100644
--- a/emb/pastilda/app/app.cpp
+++ b/emb/pastilda/app/app.cpp
@@ -23,27 +23,63 @@
#include "stdio.h"
using namespace Application;
-#ifdef DEBUG
- #define DEBUG_PRINT(x) printf(x)
-#else
- #define DEBUG_PRINT(x) do {} while (0)
-#endif
-
App *app_pointer;
App::App()
{
app_pointer = this;
+
clock_setup();
systick_init();
_leds_api = new LEDS_api();
- delay_ms(1000);
-
- usb_dispatcher = new USB_dispatcher();
+ _flash = new FlashMemory();
+ usb_host = new USB_host(redirect, control_interception);
+ usb_composite = new USB_composite(_flash->flash_blocks(), _flash->flash_read, _flash->flash_write);
}
void App::process()
{
_leds_api->toggle();
- usb_dispatcher->process();
+ usb_host->poll();
+}
+
+void App::redirect(uint8_t *data, uint8_t len)
+{
+ app_pointer->usb_composite->usb_send_packet(data, len);
+}
+
+void App::control_interception()
+{
+ memset(app_pointer->key, 0, 8);
+ app_pointer->key[2] = KEY_W;
+ app_pointer->key[3] = KEY_O;
+ app_pointer->key[4] = KEY_N;
+ app_pointer->key[5] = KEY_D;
+ app_pointer->key[6] = KEY_E;
+ app_pointer->key[7] = KEY_R;
+ app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
+
+ app_pointer->key[2] = 0;
+ app_pointer->key[3] = 0;
+ app_pointer->key[4] = 0;
+ app_pointer->key[5] = 0;
+ app_pointer->key[6] = 0;
+ app_pointer->key[7] = 0;
+ app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
+
+ app_pointer->key[2] = KEY_SPACEBAR;
+ app_pointer->key[3] = KEY_W;
+ app_pointer->key[4] = KEY_O;
+ app_pointer->key[5] = KEY_M;
+ app_pointer->key[6] = KEY_A;
+ app_pointer->key[7] = KEY_N;
+ app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
+
+ app_pointer->key[2] = 0;
+ app_pointer->key[3] = 0;
+ app_pointer->key[4] = 0;
+ app_pointer->key[5] = 0;
+ app_pointer->key[6] = 0;
+ app_pointer->key[7] = 0;
+ app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
}
diff --git a/emb/pastilda/app/app.h b/emb/pastilda/app/app.h
index de77511..6f21d59 100644
--- a/emb/pastilda/app/app.h
+++ b/emb/pastilda/app/app.h
@@ -23,12 +23,18 @@
#define APP_H
#include <string.h>
+#include <usb/usb_device/usbd_composite.h>
+#include <usb/usb_host/usbh_host.h>
#include "clock.h"
#include "gpio_ext.h"
#include "systick_ext.h"
#include "leds.h"
-#include "usb_dispatcher.h"
-#include "spi_ext.h"
+#include "flash_memory.h"
+
+extern "C" {
+#include "keyboard.h"
+}
+
using namespace LEDS_API;
using namespace GPIO_CPP_Extension;
@@ -42,9 +48,15 @@ namespace Application
App();
void process();
+ static void redirect(uint8_t *data, uint8_t len);
+ static void control_interception();
+
private:
LEDS_api *_leds_api;
- USB_dispatcher *usb_dispatcher;
+ FlashMemory *_flash;
+ USB_composite *usb_composite;
+ USB_host *usb_host;
+ uint8_t key[8];
};
}
#endif
diff --git a/emb/pastilda/app/usb_dispatcher.cpp b/emb/pastilda/app/usb_dispatcher.cpp
deleted file mode 100644
index 72614d3..0000000
--- a/emb/pastilda/app/usb_dispatcher.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This file is part of the pastilda project.
- * hosted at http://github.com/thirdpin/pastilda
- *
- * Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "usb_dispatcher.h"
-
-USB_dispatcher *dispatcher_pointer;
-
-USB_dispatcher::USB_dispatcher()
-{
- dispatcher_pointer = this;
- usb_composite = new USB_composite();
- usb_host = new USB_host(redirect, control_interception);
- _interception_enabled = false;
-}
-
-void USB_dispatcher::redirect(uint8_t *data, uint8_t len)
-{
- dispatcher_pointer->usb_composite->usb_send_packet(data, len);
-}
-
-void USB_dispatcher::control_interception()
-{
- memset(dispatcher_pointer->key, 0, 8);
- dispatcher_pointer->key[2] = KEY_W;
- dispatcher_pointer->key[3] = KEY_O;
- dispatcher_pointer->key[4] = KEY_N;
- dispatcher_pointer->key[5] = KEY_D;
- dispatcher_pointer->key[6] = KEY_E;
- dispatcher_pointer->key[7] = KEY_R;
- dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
-
- dispatcher_pointer->key[2] = 0;
- dispatcher_pointer->key[3] = 0;
- dispatcher_pointer->key[4] = 0;
- dispatcher_pointer->key[5] = 0;
- dispatcher_pointer->key[6] = 0;
- dispatcher_pointer->key[7] = 0;
- dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
-
- dispatcher_pointer->key[2] = KEY_SPACEBAR;
- dispatcher_pointer->key[3] = KEY_W;
- dispatcher_pointer->key[4] = KEY_O;
- dispatcher_pointer->key[5] = KEY_M;
- dispatcher_pointer->key[6] = KEY_A;
- dispatcher_pointer->key[7] = KEY_N;
- dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
-
- dispatcher_pointer->key[2] = 0;
- dispatcher_pointer->key[3] = 0;
- dispatcher_pointer->key[4] = 0;
- dispatcher_pointer->key[5] = 0;
- dispatcher_pointer->key[6] = 0;
- dispatcher_pointer->key[7] = 0;
- dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
-}
diff --git a/emb/pastilda/app/usb_dispatcher.h b/emb/pastilda/app/usb_dispatcher.h
deleted file mode 100644
index d9d55a2..0000000
--- a/emb/pastilda/app/usb_dispatcher.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file is part of the pastilda project.
- * hosted at http://github.com/thirdpin/pastilda
- *
- * Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef USB_DISPATCHER_H
-#define USB_DISPATCHER_H
-
-#include "usbh_host.h"
-#include "usbd_composite.h"
-extern "C"
-{
-#include "keyboard.h"
-}
-
-class USB_dispatcher
-{
-public:
- USB_composite *usb_composite;
- USB_host *usb_host;
- uint8_t key[8];
-
- USB_dispatcher();
-
- static void redirect(uint8_t *data, uint8_t len);
- static void control_interception();
- void do_work();
- void process()
- {
- usb_host->poll();
- }
-private:
- bool _interception_enabled;
-
-
-};
-
-#endif
diff --git a/emb/pastilda/hw/clock.h b/emb/pastilda/clock.h
index 57ea91a..57ea91a 100644
--- a/emb/pastilda/hw/clock.h
+++ b/emb/pastilda/clock.h
diff --git a/emb/pastilda/flash/drv/SST25.cpp b/emb/pastilda/flash/drv/SST25.cpp
new file mode 100644
index 0000000..954188a
--- /dev/null
+++ b/emb/pastilda/flash/drv/SST25.cpp
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "SST25.h"
+
+SST25::SST25(SPI_ext *spi, Pinout nss_pin)
+{
+ _spi = spi;
+
+ _nss = new GPIO_ext(nss_pin);
+ _nss->mode_setup(GPIO_CPP_Extension::Mode::OUTPUT, GPIO_CPP_Extension::PullMode::NO_PULL);
+ _nss->set_output_options(GPIO_CPP_Extension::OutputType::PUSH_PULL, GPIO_CPP_Extension::Speed::FAST_50MHz);
+ _nss->set();
+}
+
+int SST25::read_sectors(uint32_t sector, uint32_t count, void *buf)
+{
+ if(sector >= (SECTOR_COUNT)) {
+ return (0);
+ }
+
+ uint32_t address = (sector * SECTOR_SIZE);
+ uint32_t data_len = SECTOR_SIZE * count;
+
+ while ((address + data_len - 1) > (MEMORY_SIZE - 1)) {
+ count -= 1;
+ data_len = SECTOR_SIZE * count;
+ }
+
+ read(address, data_len, (uint8_t*)buf);
+ return (count);
+}
+int SST25::write_sectors(uint32_t sector, uint32_t count, const void *buf)
+{
+ if(sector >= (SECTOR_COUNT)) {
+ return (0);
+ }
+
+ uint32_t start_address = (sector * SECTOR_SIZE);
+ uint32_t data_len = SECTOR_SIZE * count;
+
+ for(int i = 0; i < count; i++)
+ {
+ erase_sector(sector + i);
+ uint32_t address = ((sector + i) * SECTOR_SIZE);
+
+ for (int j = 0; j < PAGE_COUNT_IN_SECTOR; j++) {
+ page_program(address, (uint8_t*)buf, PAGE_SIZE);
+ address += PAGE_SIZE;
+ buf += PAGE_SIZE;
+ }
+ }
+ return (count);
+}
+void SST25::disable_wtite_protection()
+{
+ enable_write_status_register();
+ write_status_register(DISABLE_WRITE_PROTECTION);
+}
+
+void SST25::read(uint32_t address, uint32_t count, uint8_t* buf)
+{
+ wait_write_complete();
+ select_device();
+ uint8_t tx[4] = {OPCODE_READ, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
+ write_buffer(tx, 4);
+ uint8_t rx[count];
+ read_buffer(rx, count);
+ release_device();
+ memcpy(buf, rx, count);
+ //return (rx);
+}
+void SST25::read_high_speed(uint32_t address, uint32_t count, uint8_t* buf)
+{
+ wait_write_complete();
+ select_device();
+ uint8_t tx[5] = {OPCODE_FAST_READ, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF), DUMMY_BYTE};
+ write_buffer(tx, 5);
+ uint8_t rx[count];
+ read_buffer(rx, count);
+ release_device();
+ memcpy(buf, rx, count);
+ //return (rx);
+}
+void SST25::page_program(uint32_t address, uint8_t *data, uint16_t count)
+{
+ wait_write_complete();
+ enable_write();
+ select_device();
+ uint16_t total_size = (4 + count);
+ uint8_t tx[total_size] = {OPCODE_PAGE_PROGRAM, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
+ for (int i = 0, j = 4; i < count; i++, j++) {
+ tx[j] = data[i];
+ }
+ write_buffer(tx, total_size);
+ release_device();
+}
+void SST25::erase_sector(uint32_t sector)
+{
+ wait_write_complete();
+ enable_write();
+ uint32_t address = (sector * SECTOR_SIZE);
+ select_device();
+ uint8_t tx[4] = {OPCODE_SECTOR_ERASE, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
+ write_buffer(tx, 4);
+ release_device();
+}
+void SST25::erase_block_32K(uint32_t start_sector)
+{
+ wait_write_complete();
+ enable_write();
+ uint32_t address = (start_sector * SECTOR_SIZE);
+ select_device();
+ uint8_t tx[4] = {OPCODE_BLOCK_ERASE_32K, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
+ write_buffer(tx, 4);
+ release_device();
+}
+void SST25::erase_block_64K(uint32_t start_sector)
+{
+ wait_write_complete();
+ enable_write();
+ uint32_t address = (start_sector * SECTOR_SIZE);
+ select_device();
+ uint8_t tx[4] = {OPCODE_BLOCK_ERASE_64K, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
+ write_buffer(tx, 4);
+ release_device();
+}
+void SST25::erase_full_chip()
+{
+ wait_write_complete();
+ enable_write();
+ select_device();
+ _spi->send(OPCODE_CHIP_ERASE);
+ release_device();
+}
+uint8_t SST25::read_status_register()
+{
+ select_device();
+ uint8_t tx[1] = {OPCODE_RDSR};
+ write_buffer(tx, 1);
+ uint8_t rx[1];
+ read_buffer(rx, 1);
+ release_device();
+ return (rx[0]);
+}
+void SST25::enable_write()
+{
+ wait_write_complete();
+ select_device();
+ _spi->send(OPCODE_WREN);
+ release_device();
+}
+void SST25::disable_write()
+{
+ wait_write_complete();
+ select_device();
+ _spi->send(OPCODE_WRDI);
+ release_device();
+}
+void SST25::enable_write_status_register()
+{
+ //wait_write_complete();
+ select_device();
+ _spi->send(OPCODE_EWSR);
+ release_device();
+}
+void SST25::write_status_register(uint8_t data)
+{
+ //wait_write_complete();
+ select_device();
+ uint8_t tx[2] = {OPCODE_WRSR, data};
+ write_buffer(tx, 2);
+ release_device();
+}
+uint16_t SST25::read_id()
+{
+ select_device();
+ uint8_t tx[4] = {OPCODE_RDID_ALT, 0, 0, 0};
+ write_buffer(tx, 4);
+ uint8_t rx[2];
+ read_buffer(rx, 2);
+ release_device();
+ return ((rx[0] << 8) | rx[1]);
+}
+uint32_t SST25::read_jedec_id()
+{
+ select_device();
+ uint8_t tx[1] = {OPCODE_JEDEC_ID};
+ write_buffer(tx, 1);
+ uint8_t rx[3];
+ read_buffer(rx, 3);
+ release_device();
+ return ((rx[0] << 16) | (rx[1] << 8) | rx[3]);
+}
+
+void SST25::select_device()
+{
+ _nss->clear();
+ while(_spi->get_flag_status(Flag::BUSY_FLAG));
+}
+void SST25::release_device()
+{
+ _nss->set();
+}
+void SST25::write_buffer(const uint8_t *buf, int len)
+{
+ while(len--)
+ _spi->send(*buf++);
+}
+void SST25::read_buffer(uint8_t *buf, int len)
+{
+ uint8_t res = _spi->read();
+ while(len--)
+ *buf++ = _spi->read();
+}
+void SST25::wait_write_complete()
+{
+ uint8_t status = read_status_register();
+ while (status & SST25_SR_BUSY) {
+ status = read_status_register();
+ }
+}
diff --git a/emb/pastilda/flash/drv/SST25.h b/emb/pastilda/flash/drv/SST25.h
new file mode 100644
index 0000000..3b38fb4
--- /dev/null
+++ b/emb/pastilda/flash/drv/SST25.h
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SST25_H
+#define SST25_H
+
+#include <string.h>
+
+#include "spi_ext.h"
+#include "gpio_ext.h"
+
+using namespace SPI_CPP_Extension;
+
+constexpr uint8_t OPCODE_READ = 0x03; /* Read data bytes 3 0 >=1 */
+constexpr uint8_t OPCODE_FAST_READ_DUAL_IO = 0xBB;
+constexpr uint8_t OPCODE_FAST_READ_DUAL_OUTPUT = 0x3B;
+constexpr uint8_t OPCODE_FAST_READ = 0x0B; /* Higher speed read 3 1 >=1 */
+constexpr uint8_t OPCODE_SECTOR_ERASE = 0x20; /* 4Kb Sector erase 3 0 0 */
+constexpr uint8_t OPCODE_BLOCK_ERASE_32K = 0x52; /* 32Kbit block Erase 3 0 0 */
+constexpr uint8_t OPCODE_BLOCK_ERASE_64K = 0xD8; /* 64Kbit block Erase 3 0 0 */
+constexpr uint8_t OPCODE_CHIP_ERASE = 0xC7; /* Chip erase 0 0 0 */
+constexpr uint8_t OPCODE_CHIP_ERASE_ALT = 0x60; /* Chip erase (alternate) 0 0 0 */
+constexpr uint8_t OPCODE_PAGE_PROGRAM = 0x02; /* Byte program 3 0 1 */
+constexpr uint8_t OPCODE_PAGE_PROGRAM_DUAL = 0xA2; /* Auto address increment 3 0 >=2 */
+constexpr uint8_t OPCODE_RDSR = 0x05; /* Read status register 0 0 >=1 */
+constexpr uint8_t OPCODE_EWSR = 0x50; /* Write enable status 0 0 0 */
+constexpr uint8_t OPCODE_WRSR = 0x01; /* Write Status Register 0 0 1 */
+constexpr uint8_t OPCODE_WREN = 0x06; /* Write Enable 0 0 0 */
+constexpr uint8_t OPCODE_WRDI = 0x04; /* Write Disable 0 0 0 */
+constexpr uint8_t OPCODE_RDID = 0xAB; /* Read Identification 0 0 >=1 */
+constexpr uint8_t OPCODE_RDID_ALT = 0x90; /* Read Identification (alt) 0 0 >=1 */
+constexpr uint8_t OPCODE_JEDEC_ID = 0x9F; /* JEDEC ID read 0 0 >=3 */
+constexpr uint8_t OPCODE_EHLD = 0xAA;
+constexpr uint8_t OPCODE_READ_SID = 0x88;
+constexpr uint8_t OPCODE_PROGRAM_SID = 0xA5;
+constexpr uint8_t OPCODE_LOCKOUT_SID = 0x85;
+
+constexpr uint8_t SST25_MANUFACTURER = 0xBF; /* SST manufacturer ID */
+constexpr uint8_t SST25_DEVICE_ID = 0x4B; /* SSTVF032B device ID */
+
+constexpr uint8_t SST25_JEDEC_MANUFACTURER = 0xBF; /* SST manufacturer ID */
+constexpr uint8_t SST25_JEDEC_MEMORY_TYPE = 0x25; /* SST25 memory type */
+constexpr uint8_t SST25_JEDEC_MEMORY_CAPACITY = 0x4B; /* SST25VF032B memory capacity */
+
+constexpr uint8_t SST25_SR_BUSY = (0x1 << 0); /* Bit 0: Write in progress */
+constexpr uint8_t SST25_SR_WEL = (0x1 << 1); /* Bit 1: Write enable latch bit */
+constexpr uint8_t SST25_SR_BP_MASK = (0xF << 2);
+constexpr uint8_t SST25_SR_BP_NONE = (0x0 << 2);/* Unprotected */
+constexpr uint8_t SST25_SR_BP_UPPER128 = (0x1 << 2); /* Upper 64th */
+constexpr uint8_t SST25_SR_BP_UPPER64 = (0x2 << 2); /* Upper 32nd */
+constexpr uint8_t SST25_SR_BP_UPPER32 = (0x3 << 2); /* Upper 16th */
+constexpr uint8_t SST25_SR_BP_UPPER16 = (0x4 << 2); /* Upper 8th */
+constexpr uint8_t SST25_SR_BP_UPPER8 = (0x5 << 2); /* Upper quarter */
+constexpr uint8_t SST25_SR_BP_UPPER4 = (0x6 << 2); /* Upper half */
+constexpr uint8_t SST25_SR_BP_UPPER2 = (0x7 << 2); /* All sectors */
+constexpr uint8_t SST25_SR_BP_ALL = (0x8 << 2); /* All sectors */
+constexpr uint8_t SST25_SR_SEC = (0x1 << 6); /* Bit 6: Auto Address increment programming */
+constexpr uint8_t SST25_SR_BPL = (0x1 << 7); /* Bit 7: Status register write protect */
+
+constexpr uint8_t SST25_ERASED_STATE = 0xFF; /* State of FLASH when erased */
+constexpr uint8_t DUMMY_BYTE = 0xFE;
+
+constexpr uint16_t DISABLE_WRITE_PROTECTION = 0x00;
+constexpr uint16_t SECTOR_SIZE = 4096;
+constexpr uint32_t MEMORY_SIZE = 0x800000;
+constexpr uint16_t SECTOR_COUNT = MEMORY_SIZE / SECTOR_SIZE;
+constexpr uint16_t PAGE_SIZE = 256;
+constexpr uint16_t PAGE_COUNT_IN_SECTOR = 16;
+
+
+class SST25
+{
+public:
+ SST25(SPI_ext *spi, Pinout nss_pin);
+ int read_sectors(uint32_t sector, uint32_t count, void *buf);
+ int write_sectors(uint32_t sector, uint32_t count, const void *buf);
+ void disable_wtite_protection();
+
+ void read(uint32_t address, uint32_t count, uint8_t* buf);
+ void read_high_speed(uint32_t address, uint32_t count, uint8_t* buf);
+ void page_program(uint32_t address, uint8_t *data, uint16_t count);
+ void erase_sector(uint32_t sector);
+ void erase_block_32K(uint32_t start_sector);
+ void erase_block_64K(uint32_t start_sector);
+ void erase_full_chip();
+ ///TODO: 3 SID functions
+ uint8_t read_status_register();
+ void enable_write();
+ void disable_write();
+ void enable_write_status_register();
+ void write_status_register(uint8_t data);
+ ///TODO: enable HOLD
+ uint16_t read_id();
+ uint32_t read_jedec_id();
+
+private:
+ SPI_ext *_spi;
+ GPIO_ext *_nss;
+
+ void select_device();
+ void release_device();
+ void write_buffer(const uint8_t *buf, int len);
+ void read_buffer(uint8_t *buf, int len);
+ void wait_write_complete();
+};
+
+#endif
diff --git a/emb/pastilda/flash/flash_memory.cpp b/emb/pastilda/flash/flash_memory.cpp
new file mode 100644
index 0000000..2afa1d8
--- /dev/null
+++ b/emb/pastilda/flash/flash_memory.cpp
@@ -0,0 +1,218 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "flash_memory.h"
+
+FlashMemory *flash_pointer;
+
+FlashMemory::FlashMemory()
+{
+ flash_pointer = this;
+
+ SPI_CPP_Extension::SPI_Conf sst25_conf = { 1, PA7, PA6, PA5 };
+ _spi = new SPI_ext(sst25_conf);
+
+ _spi->reset();
+ _spi->disable();
+ _spi->set_master_mode();
+ _spi->set_baudrate_prescaler(BAUDRATE_FPCLK_DIV_2);
+ _spi->set_standard_mode(MODE_0);
+ _spi->set_data_drame_format(DFF_8BIT);
+ _spi->set_bit_position(MSB_FIRST);
+ _spi->enable_ss_output();
+ _spi->set_software_slave_management(State::ENABLE);
+ _spi->set_nss(HIGH);
+ _spi->enable();
+
+ _sst25 = new SST25(_spi, PA4);
+ _sst25->disable_wtite_protection();
+
+ FatState state = _get_fat_state();
+ if (state == FatState::FAT_ERROR) {
+ _set_fat_system_region();
+ }
+}
+
+uint16_t FlashMemory::get_sector_size(const struct block_device *dev)
+{
+ (void)dev;
+ return (FAKE_SECTOR_SIZE);
+}
+
+int FlashMemory::read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf)
+{
+ (void)dev;
+ uint32_t end_sector = sector + count - 1;
+ if (end_sector >= FAKE_SECTOR_COUNT) {
+ return (0);
+ }
+
+ uint32_t real_start_sector = sector / 8;
+ uint32_t real_end_sector = end_sector / 8;
+ uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
+ uint32_t real_start_sector_part = (sector % 8);
+
+ uint32_t data_size = real_sector_count * SECTOR_SIZE;
+ uint8_t data[data_size];
+
+ flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, data);
+
+ uint32_t start_address = real_start_sector_part * FAKE_SECTOR_SIZE;
+ uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
+
+ for (int i = start_address, j = 0; i < end_address; i++, j++) {
+ ((uint8_t*)buf)[j] = data[i];
+ }
+
+ return (count);
+}
+
+int FlashMemory::write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf)
+{
+ (void)dev;
+ uint32_t end_sector = (sector + count - 1);
+ if (end_sector >= FAKE_SECTOR_COUNT) {
+ return (0);
+ }
+
+ uint32_t real_start_sector = sector / 8;
+ uint32_t real_end_sector = end_sector / 8;
+ uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
+ uint32_t real_start_sector_part = (sector % 8);
+
+ uint32_t copy_size = real_sector_count * SECTOR_SIZE;
+ uint8_t sector_copy[copy_size];
+
+ flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, sector_copy);
+
+ uint32_t start_address = real_start_sector_part * FAKE_SECTOR_SIZE;
+ uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
+
+ for (int i = start_address, j = 0; i < end_address; i++, j++) {
+ sector_copy[i] = ((uint8_t*)buf)[j];
+ }
+
+ flash_pointer->_sst25->write_sectors(real_start_sector, real_sector_count, sector_copy);
+ return (count);
+}
+
+int FlashMemory::flash_read(uint32_t lba, uint8_t *copy_to)
+{
+ memset(copy_to, 0, FAKE_SECTOR_SIZE);
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ read_sectors(0, lba, 1, copy_to);
+ return (0);
+ }
+}
+
+void FlashMemory::erase_chip()
+{
+ _sst25->erase_full_chip();
+}
+int FlashMemory::flash_write(uint32_t lba, const uint8_t *copy_from)
+{
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ write_sectors(0, lba, 1, copy_from);
+ return (0);
+ }
+}
+int FlashMemory::flash_blocks(void)
+{
+ return (FAKE_SECTOR_COUNT);
+}
+FatState FlashMemory::_get_fat_state()
+{
+ uint8_t buf[2];
+ _sst25->read(510, 2, buf);
+ uint16_t signature = ((buf[0] << 8) | buf[1]);
+ if (signature == BOOT_SIGNATURE) {
+ return (FatState::FAT_READY);
+ }
+
+ return (FatState::FAT_ERROR);
+}
+void FlashMemory::_set_fat_system_region()
+{
+ _sst25->erase_full_chip();
+ _set_boot_region();
+ _set_fat_region();
+ _set_root_dir_region();
+}
+
+void FlashMemory::_set_boot_region()
+{
+ uint8_t copy_to[BOOT_SIZE];
+ memset(copy_to, 0, BOOT_SIZE);
+
+ uint8_t BootSector[] = {
+ 0xEB, 0x58, 0x90, // code to jump to the bootstrap code
+ 0x57, 0x49, 0x4E, 0x49, 0x4D, 0x41, 0x47, 0x45, // OEM ID
+ 0x00, 0x02, // bytes per sector
+ 0x08, // sectors per cluster (0x04)
+ 0x01, 0x00, // # of reserved sectors (1 boot sector)
+ 0x02, // FAT copies (2)
+ 0x00, 0x02, // root entries (512)
+ 0x00, 0x40, // total number of sectors
+ 0xF8, // media descriptor (0xF8 = Fixed disk)
+ 0x08, 0x00, // sectors per FAT (16)
+ 0x00, 0x00, // sectors per track (0)
+ 0x00, 0x00, // number of heads (0)
+ 0x00, 0x00, 0x00, 0x00, // hidden sectors (0)
+ 0x00, 0x00, 0x00, 0x00, // large number of sectors (0)
+ 0x80, // drive number (0)
+ 0x00, // reserved
+ 0x29, // extended boot signature
+ 0x10, 0x5C, 0xD1, 0x34, // volume serial number
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // volume label
+ 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20 // filesystem type
+ };
+
+ memcpy(copy_to, BootSector, sizeof(BootSector));
+ copy_to[BOOT_SIZE - 2] = 0x55;
+ copy_to[BOOT_SIZE - 1] = 0xAA;
+
+ write_sectors(0, BOOT_SECTOR, BOOT_SECTOR_COUNT, copy_to);
+}
+void FlashMemory::_set_fat_region()
+{
+ uint8_t copy_to[FAT_SIZE];
+
+ memset(copy_to, 0, FAT_SIZE);
+ copy_to[0] = 0xF8;
+ copy_to[1] = 0xFF;
+ copy_to[2] = 0xFF;
+ copy_to[3] = 0xFF;
+
+ write_sectors(0, FAT1_SECTOR, FAT_SECTOR_COUNT, copy_to);
+ write_sectors(0, FAT2_SECTOR, FAT_SECTOR_COUNT, copy_to);
+}
+void FlashMemory::_set_root_dir_region()
+{
+ uint8_t copy_to[ROOT_SIZE];
+ memset(copy_to, 0, ROOT_SIZE);
+ write_sectors(0, 17, ROOT_SECTOR_COUNT, copy_to);
+}
diff --git a/emb/pastilda/flash/flash_memory.h b/emb/pastilda/flash/flash_memory.h
new file mode 100644
index 0000000..681ae22
--- /dev/null
+++ b/emb/pastilda/flash/flash_memory.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLASH_MEMORY_H
+#define FLASH_MEMORY_H
+
+#include <string.h>
+
+extern "C"
+{
+#include "blockdev.h"
+#include "openfat.h"
+#include "mbr.h"
+}
+
+#include "spi_ext.h"
+#include "SST25.h"
+
+using namespace SPI_CPP_Extension;
+
+#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
+#define QBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
+
+constexpr uint16_t FAKE_SECTOR_SIZE = 512;
+constexpr uint16_t FAKE_SECTOR_COUNT = 16384; //(MEMORY_SIZE / FAKE_SECTOR_SIZE);
+constexpr uint16_t BOOT_SIGNATURE = 0x55AA;
+
+constexpr uint16_t BYTES_PER_SECTOR = 512;
+constexpr uint16_t SECTORS_PER_CLUSTER = 4;
+constexpr uint16_t RESERVED_SECTORS = 1;
+constexpr uint16_t FAT_COPIES = 2;
+constexpr uint16_t ROOT_ENTRIES = 512;
+
+constexpr uint16_t BOOT_SIZE = 512;
+constexpr uint16_t BOOT_SECTOR = 0;
+constexpr uint16_t BOOT_SECTOR_COUNT = 1;
+
+constexpr uint16_t FAT_SIZE = 4096;
+constexpr uint16_t FAT_SECTOR_COUNT = 8;
+constexpr uint16_t FAT1_SECTOR = 1;
+constexpr uint16_t FAT2_SECTOR = 1 + FAT_SECTOR_COUNT;
+
+constexpr uint16_t ROOT_SIZE = 16384;
+constexpr uint16_t ROOT_SECTOR_COUNT = 32;
+
+typedef enum {
+ FAT_READY,
+ FAT_ERROR
+}FatState;
+
+class FlashMemory
+{
+public:
+ FlashMemory();
+ static uint16_t get_sector_size(const struct block_device *dev);
+ static int read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf);
+ static int write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf);
+
+ void erase_chip();
+
+ static int flash_read(uint32_t lba, uint8_t *copy_to);
+ static int flash_write(uint32_t lba, const uint8_t *copy_from);
+ static int flash_blocks(void);
+
+ void print_tree();
+
+private:
+ SST25 *_sst25;
+ SPI_ext *_spi;
+
+ struct block_device dev;
+ struct block_mbr_partition part;
+ struct fat_vol_handle vol;
+ struct fat_file_handle dir;
+ struct fat_file_handle file;
+
+ FatState _get_fat_state();
+ void _set_fat_system_region();
+ void _set_boot_region();
+ void _set_fat_region();
+ void _set_root_dir_region();
+};
+
+#endif
diff --git a/emb/pastilda/hw/usb_device/ramdisk.c b/emb/pastilda/hw/usb_device/ramdisk.c
deleted file mode 100644
index 15ea8a1..0000000
--- a/emb/pastilda/hw/usb_device/ramdisk.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <string.h>
-#include "ramdisk.h"
-
-#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
-#define QBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF),\
- (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
-
-// filesystem size is 512kB (1024 * SECTOR_SIZE)
-#define SECTOR_COUNT 1024
-#define SECTOR_SIZE 512
-#define BYTES_PER_SECTOR 512
-#define SECTORS_PER_CLUSTER 4
-#define RESERVED_SECTORS 1
-#define FAT_COPIES 2
-#define ROOT_ENTRIES 512
-#define ROOT_ENTRY_LENGTH 32
-#define FILEDATA_START_CLUSTER 3
-#define DATA_REGION_SECTOR (RESERVED_SECTORS + FAT_COPIES + \
- (ROOT_ENTRIES * ROOT_ENTRY_LENGTH) / BYTES_PER_SECTOR)
-#define FILEDATA_START_SECTOR (DATA_REGION_SECTOR + \
- (FILEDATA_START_CLUSTER - 2) * SECTORS_PER_CLUSTER)
-
-// filesize is 64kB (128 * SECTOR_SIZE)
-#define FILEDATA_SECTOR_COUNT 128
-
-uint8_t BootSector[] = {
- 0xEB, 0x3C, 0x90, // code to jump to the bootstrap code
- 'm', 'k', 'd', 'o', 's', 'f', 's', 0x00, // OEM ID
- WBVAL(BYTES_PER_SECTOR), // bytes per sector
- SECTORS_PER_CLUSTER, // sectors per cluster
- WBVAL(RESERVED_SECTORS), // # of reserved sectors (1 boot sector)
- FAT_COPIES, // FAT copies (2)
- WBVAL(ROOT_ENTRIES), // root entries (512)
- WBVAL(SECTOR_COUNT), // total number of sectors
- 0xF8, // media descriptor (0xF8 = Fixed disk)
- 0x01, 0x00, // sectors per FAT (1)
- 0x20, 0x00, // sectors per track (32)
- 0x40, 0x00, // number of heads (64)
- 0x00, 0x00, 0x00, 0x00, // hidden sectors (0)
- 0x00, 0x00, 0x00, 0x00, // large number of sectors (0)
- 0x00, // drive number (0)
- 0x00, // reserved
- 0x29, // extended boot signature
- 0x69, 0x17, 0xAD, 0x53, // volume serial number
- 'R', 'A', 'M', 'D', 'I', 'S', 'K', ' ', ' ', ' ', ' ', // volume label
- 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' // filesystem type
-};
-
-uint8_t FatSector[] = {
- 0xF8, 0xFF, 0xFF, 0x00, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00,
- 0x09, 0xA0, 0x00, 0x0B, 0xC0, 0x00, 0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01,
- 0x11, 0x20, 0x01, 0x13, 0x40, 0x01, 0x15, 0x60, 0x01, 0x17, 0x80, 0x01,
- 0x19, 0xA0, 0x01, 0x1B, 0xC0, 0x01, 0x1D, 0xE0, 0x01, 0x1F, 0x00, 0x02,
- 0x21, 0x20, 0x02, 0x23, 0x40, 0x02, 0x25, 0x60, 0x02, 0x27, 0x80, 0x02,
- 0x29, 0xA0, 0x02, 0x2B, 0xC0, 0x02, 0x2D, 0xE0, 0x02, 0x2F, 0x00, 0x03,
- 0x31, 0x20, 0x03, 0x33, 0x40, 0x03, 0x35, 0x60, 0x03, 0x37, 0x80, 0x03,
- 0x39, 0xA0, 0x03, 0x3B, 0xC0, 0x03, 0x3D, 0xE0, 0x03, 0x3F, 0x00, 0x04,
- 0x41, 0x20, 0x04, 0x43, 0x40, 0x04, 0x45, 0x60, 0x04, 0x47, 0x80, 0x04,
- 0x49, 0xA0, 0x04, 0x4B, 0xC0, 0x04, 0x4D, 0xE0, 0x04, 0x4F, 0x00, 0x05,
- 0x51, 0x20, 0x05, 0x53, 0x40, 0x05, 0x55, 0x60, 0x05, 0x57, 0x80, 0x05,
- 0x59, 0xA0, 0x05, 0x5B, 0xC0, 0x05, 0x5D, 0xE0, 0x05, 0x5F, 0x00, 0x06,
- 0x61, 0x20, 0x06, 0x63, 0x40, 0x06, 0x65, 0x60, 0x06, 0x67, 0x80, 0x06,
- 0x69, 0xA0, 0x06, 0x6B, 0xC0, 0x06, 0x6D, 0xE0, 0x06, 0x6F, 0x00, 0x07,
- 0x71, 0x20, 0x07, 0x73, 0x40, 0x07, 0x75, 0x60, 0x07, 0x77, 0x80, 0x07,
- 0x79, 0xA0, 0x07, 0x7B, 0xC0, 0x07, 0x7D, 0xE0, 0x07, 0x7F, 0x00, 0x08,
- 0x81, 0x20, 0x08, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-uint8_t DirSector[] = {
- // long filename entry
- 0x41, // sequence number
- WBVAL('r'), WBVAL('a'), WBVAL('m'), WBVAL('d'), WBVAL('i'), // five name characters in UTF-16
- 0x0F, // attributes
- 0x00, // type
- 0x00, // checksum of DOS filename (computed in ramdisk_init)
- WBVAL('s'), WBVAL('k'), WBVAL('.'), WBVAL('d'), WBVAL('a'), WBVAL('t'), // six name characters in UTF-16
- 0x00, 0x00, // first cluster
- WBVAL(0), WBVAL(0), // two name characters in UTF-16
- // actual entry
- 'R', 'A', 'M', 'D', 'I', 'S', 'K', ' ', // filename
- 'D', 'A', 'T', // extension
- 0x20, // attribute byte
- 0x00, // reserved for Windows NT
- 0x00, // creation millisecond
- 0xCE, 0x01, // creation time
- 0x86, 0x41, // creation date
- 0x86, 0x41, // last access date
- 0x00, 0x00, // reserved for FAT32
- 0xCE, 0x01, // last write time
- 0x86, 0x41, // last write date
- WBVAL(FILEDATA_START_CLUSTER), // start cluster
- QBVAL(FILEDATA_SECTOR_COUNT * SECTOR_SIZE) // file size in bytes
-};
-
-static uint8_t ramdata[FILEDATA_SECTOR_COUNT * SECTOR_SIZE];
-
-int ramdisk_init(void)
-{
- uint32_t i = 0;
-
- // compute checksum in the directory entry
- uint8_t chk = 0;
- for (i = 32; i < 43; i++) {
- chk = (((chk & 1) << 7) | ((chk & 0xFE) >> 1)) + DirSector[i];
- }
- DirSector[13] = chk;
-
- // fill ramdata
- const uint8_t text[] = "USB Mass Storage Class example. ";
- i = 0;
- while (i < sizeof(ramdata)) {
- ramdata[i] = text[i % (sizeof(text) -1)];
- i++;
- }
- return (0);
-}
-
-int ramdisk_read(uint32_t lba, uint8_t *copy_to)
-{
- memset(copy_to, 0, SECTOR_SIZE);
- switch (lba) {
- case 0: // sector 0 is the boot sector
- memcpy(copy_to, BootSector, sizeof(BootSector));
- copy_to[SECTOR_SIZE - 2] = 0x55;
- copy_to[SECTOR_SIZE - 1] = 0xAA;
- break;
- case 1: // sector 1 is FAT 1st copy
- case 2: // sector 2 is FAT 2nd copy
- memcpy(copy_to, FatSector, sizeof(FatSector));
- break;
- case 3: // sector 3 is the directory entry
- memcpy(copy_to, DirSector, sizeof(DirSector));
- break;
- default:
- // ignore reads outside of the data section
- if (lba >= FILEDATA_START_SECTOR && lba < FILEDATA_START_SECTOR + FILEDATA_SECTOR_COUNT) {
- memcpy(copy_to, ramdata + (lba - FILEDATA_START_SECTOR) * SECTOR_SIZE, SECTOR_SIZE);
- }
- break;
- }
- return (0);
-}
-
-int ramdisk_write(uint32_t lba, const uint8_t *copy_from)
-{
- (void)lba;
- (void)copy_from;
- // ignore writes
- return (0);
-}
-
-int ramdisk_blocks(void)
-{
- return (SECTOR_COUNT);
-}
diff --git a/emb/pastilda/hw/usb_device/ramdisk.h b/emb/pastilda/hw/usb_device/ramdisk.h
deleted file mode 100644
index 852dc92..0000000
--- a/emb/pastilda/hw/usb_device/ramdisk.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef RAMDISK_H
-#define RAMDISK_H
-
-#include <stdint.h>
-#include <libopencm3/cm3/common.h>
-
-BEGIN_DECLS
-extern int ramdisk_init(void);
-extern int ramdisk_read(uint32_t lba, uint8_t *copy_to);
-extern int ramdisk_write(uint32_t lba, const uint8_t *copy_from);
-extern int ramdisk_blocks(void);
-END_DECLS
-
-#endif
diff --git a/emb/pastilda/hw/keyboard.h b/emb/pastilda/keyboard.h
index 7a59e41..7a59e41 100644
--- a/emb/pastilda/hw/keyboard.h
+++ b/emb/pastilda/keyboard.h
diff --git a/emb/pastilda/lib/libopenfat/bpb.h b/emb/pastilda/lib/libopenfat/bpb.h
new file mode 100644
index 0000000..6593f14
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/bpb.h
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Boot Sector / BIOS Parameter Block definitions.
+ * Convenience functions for calculations.
+ */
+
+#ifndef __BPB_H
+#define __BPB_H
+
+#include <stdint.h>
+#include "openfat/leaccess.h"
+
+/* Boot sector fields common to FAT12/FAT16/FAT32 */
+struct bpb_common {
+ uint8_t boot_jmp[3];
+ char oem_name[8];
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sector_count;
+ uint8_t num_fats;
+ uint16_t root_entry_count;
+ uint16_t total_sectors_16;
+ uint8_t media;
+ uint16_t fat_size_16;
+ uint16_t sectors_per_track;
+ uint16_t num_heads;
+ uint32_t hidden_sectors;
+ uint32_t total_sectors_32;
+} __attribute__((packed));
+
+/* Boot sector fields only in FAT12/FAT16 */
+struct bpb_fat12_16 {
+ struct bpb_common common;
+ uint8_t drive_num;
+ uint8_t Reserved1;
+ uint8_t boot_sig;
+ uint32_t volume_id;
+ char volume_label[11];
+ char fs_type[8];
+} __attribute__((packed));
+
+/* Boot sector fields only in FAT32 */
+struct bpb_fat32 {
+ struct bpb_common common;
+ uint32_t fat_size_32;
+ uint16_t ext_flags;
+ uint16_t fs_version;
+ uint32_t root_cluster;
+ uint16_t fs_info;
+ uint16_t bk_boot_sec;
+ uint8_t Reserved[12];
+ uint8_t drive_num;
+ uint8_t Reserved1;
+ uint8_t boot_sig;
+ uint32_t volume_id;
+ char volume_label[11];
+ char fs_type[8];
+} __attribute__((packed));
+
+
+static inline uint32_t
+_bpb_root_dir_sectors(struct bpb_common *bpb)
+{
+ return ((__get_le16(&bpb->root_entry_count) * 32) +
+ (__get_le16(&bpb->bytes_per_sector) - 1)) /
+ __get_le16(&bpb->bytes_per_sector);
+}
+
+static inline uint32_t
+_bpb_fat_size(struct bpb_common *bpb)
+{
+ uint32_t fat_size = __get_le16(&bpb->fat_size_16);
+ if(fat_size == 0)
+ fat_size = __get_le32(&((struct bpb_fat32 *)bpb)->fat_size_32);
+
+ return fat_size;
+}
+
+static inline uint32_t
+_bpb_first_data_sector(struct bpb_common *bpb)
+{
+ return __get_le16(&bpb->reserved_sector_count) +
+ (bpb->num_fats * _bpb_fat_size(bpb))
+ + _bpb_root_dir_sectors(bpb);
+}
+
+static inline uint32_t
+_bpb_first_sector_of_cluster(struct bpb_common *bpb, uint32_t n)
+{
+ return ((n - 2) * bpb->sectors_per_cluster) +
+ _bpb_first_data_sector(bpb);
+}
+
+enum fat_type {
+ FAT_TYPE_FAT12 = 12,
+ FAT_TYPE_FAT16 = 16,
+ FAT_TYPE_FAT32 = 32,
+};
+
+static inline uint32_t _bpb_cluster_count(struct bpb_common *bpb)
+{
+ uint32_t tot_sec = __get_le16(&bpb->total_sectors_16);
+ if(tot_sec == 0)
+ tot_sec = __get_le32(&bpb->total_sectors_32);
+
+ uint32_t data_sec = tot_sec -
+ __get_le16(&bpb->reserved_sector_count) -
+ (bpb->num_fats * _bpb_fat_size(bpb)) -
+ _bpb_root_dir_sectors(bpb);
+
+ return data_sec / bpb->sectors_per_cluster;
+}
+
+/* FAT type is determined by count of clusters */
+static inline enum fat_type
+fat_type(struct bpb_common *bpb)
+{
+ uint32_t cluster_count = _bpb_cluster_count(bpb);
+ if(cluster_count < 4085) {
+ return FAT_TYPE_FAT12;
+ } else if(cluster_count < 65525) {
+ return FAT_TYPE_FAT16;
+ }
+ return FAT_TYPE_FAT32;
+}
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/direntry.c b/emb/pastilda/lib/libopenfat/direntry.c
new file mode 100644
index 0000000..46dfc35
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/direntry.c
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FAT Directory .
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "openfat.h"
+
+#include "openfat/leaccess.h"
+#include "openfat/blockdev.h"
+#include "fat_core.h"
+#include "direntry.h"
+
+#define LONG_NAME_SUPPORT
+
+#ifdef LONG_NAME_SUPPORT
+uint8_t _fat_dirent_chksum(uint8_t *dosname)
+{
+ uint8_t sum = 0;
+ int i;
+
+ for (i = 0; i < 11; i++)
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *dosname++;
+
+ return sum;
+}
+
+/* Used to convert W95 UTF-16 filenames to ascii.
+ * 0 means terminating null reached.
+ * 1 means converted to end on input.
+ * 2 means conversion error.
+ */
+static int ascii_from_utf16(char *ascii, const uint16_t *utf16, int count)
+{
+ uint16_t tmp;
+ while(count--) {
+ tmp = __get_le16(utf16++);
+ if(tmp > 127)
+ return 2;
+ *ascii++ = tmp;
+ if(tmp == 0)
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+int fat_readdir(struct fat_file_handle *h, struct dirent *ent)
+{
+#ifdef LONG_NAME_SUPPORT
+ uint16_t csum = -1;
+#endif
+ struct fat_sdirent fatent;
+ int i, j;
+
+ while(fat_read(h, &fatent, sizeof(fatent)) == sizeof(fatent)) {
+
+ if(fatent.name[0] == 0)
+ return -1; /* Empty entry, end of directory */
+ if(fatent.name[0] == (char)0xe5)
+ continue; /* Deleted entry */
+ if(fatent.attr == FAT_ATTR_VOLUME_ID)
+ continue; /* Ignore volume id entry */
+ if(fatent.attr == FAT_ATTR_LONG_NAME) {
+#ifdef LONG_NAME_SUPPORT
+ struct fat_ldirent *ld = (void*)&fatent;
+ if(ld->ord & FAT_LAST_LONG_ENTRY) {
+ memset(ent->d_name, 0, sizeof(ent->d_name));
+ csum = ld->checksum;
+ }
+ if(csum != ld->checksum) /* Abandon orphaned entry */
+ csum = -1;
+
+ i = ((ld->ord & 0x3f) - 1) * 13;
+
+ /* If entries can't be converted to ASCII, abandon
+ * the long filename. DOS 8.3 name will be returned.
+ * Not pretty... */
+ switch(ascii_from_utf16(&ent->d_name[i], ld->name1, 5))
+ { case 0: continue; case 2: csum = -1; }
+ switch(ascii_from_utf16(&ent->d_name[i+5], ld->name2, 6))
+ { case 0: continue; case 2: csum = -1; }
+ switch(ascii_from_utf16(&ent->d_name[i+11], ld->name3, 2))
+ { case 0: continue; case 2: csum = -1; }
+#endif
+ continue;
+ }
+#ifdef LONG_NAME_SUPPORT
+ if(csum != _fat_dirent_chksum((uint8_t*)fatent.name))
+ ent->d_name[0] = 0;
+
+ if(ent->d_name[0] == 0) {
+#endif
+ for(i = 0, j = 0; i < 11; i++, j++) {
+ ent->d_name[j] = tolower(fatent.name[i]);
+ if(fatent.name[i] == ' ') {
+ ent->d_name[j] = '.';
+ while((fatent.name[++i] == ' ') && (i < 11));
+ }
+ }
+ if(ent->d_name[j-1] == '.')
+ ent->d_name[j-1] = 0;
+
+ ent->d_name[j] = 0;
+#ifdef LONG_NAME_SUPPORT
+ }
+#endif
+ /* Non-standard */
+ ent->fat_attr = fatent.attr;
+ memcpy(ent->fat_sname, fatent.name, 11);
+
+ return 0;
+ }
+ return -1;
+}
+
+/* Seek to a place in the directory suitable for writing 'entries' new
+ * directory entries. Called when creating files. */
+int _fat_dir_seek_empty(struct fat_file_handle *dir, int entries)
+{
+ uint32_t pos = 0;
+ struct fat_sdirent ent;
+ int i = 0;
+
+ fat_lseek(dir, 0, SEEK_SET);
+
+ while(fat_read(dir, &ent, sizeof(ent)) == sizeof(ent)) {
+ if(ent.name[0] == 0) /* Empty entry, end of directory */
+ break;
+ if(ent.name[0] == (char)0xe5) { /* Deleted entry */
+ i++;
+ if(i == entries)
+ break;
+ continue;
+ }
+ i = 0;
+ pos = dir->position;
+ }
+
+ fat_lseek(dir, pos, SEEK_SET);
+ return 0;
+}
+
+static int fat_comparesfn(const char * name, const char *fatname)
+{
+ char canonname[11];
+ int i;
+
+ memset(canonname, ' ', sizeof(canonname));
+ if(name[0] == '.') {
+ /* Special case:
+ * Only legal names are '.' and '..' */
+ memcpy(canonname, name, strlen(name));
+ name += strlen(name);
+ } else for(i = 0; (i < 11) && *name && (*name != '/'); i++) {
+ if(*name == '.') {
+ if(i < 8) continue;
+ if(i == 8) name++;
+ }
+ canonname[i] = toupper(*name++);
+ }
+ return ((*name == 0) || (*name == '/')) && !memcmp(canonname, fatname, 11);
+}
+
+int fat_open(struct fat_vol_handle *vol, const char *name, int flags,
+ struct fat_file_handle *file)
+{
+ struct fat_file_handle *dir = (struct fat_file_handle*)&vol->cwd;
+ struct dirent dirent;
+
+ /* FIXME: Implement flags O_RDONLY, O_WRONLY, O_RDWR. */
+
+ if(strcmp(name, ".") == 0) {
+ /* Special case needed for root dir with no '.' entry */
+ memcpy(file, &vol->cwd, sizeof(*file));
+ return 0;
+ }
+
+ fat_lseek(dir, 0, SEEK_SET);
+ while(fat_readdir(dir, &dirent) == 0) {
+
+ /* Check for name match */
+ if((strcmp(name, dirent.d_name) == 0) ||
+ fat_comparesfn(name, dirent.fat_sname)) {
+ /* reread on-disk directory entry */
+ struct fat_sdirent fatent;
+ uint32_t sector;
+ uint16_t offset;
+ /* Rewind directory one entry */
+ fat_lseek(dir, -sizeof(fatent), SEEK_CUR);
+ _fat_file_sector_offset(dir, &sector, &offset);
+ if(fat_read(dir, &fatent, sizeof(fatent)) != 32)
+ return -EIO;
+
+ _fat_file_init(dir->fat, &fatent, file);
+ file->flags = flags;
+ if(!(fatent.attr & FAT_ATTR_DIRECTORY)) {
+ file->dirent_sector = sector;
+ file->dirent_offset = offset;
+ } else if(!file->first_cluster) {
+ /* Check for special case of root dir */
+ _fat_file_root(dir->fat, file);
+ }
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int fat_chdir(struct fat_vol_handle *vol, const char *name)
+{
+ return fat_open(vol, name, 0, &vol->cwd);
+}
+
diff --git a/emb/pastilda/lib/libopenfat/direntry.h b/emb/pastilda/lib/libopenfat/direntry.h
new file mode 100644
index 0000000..3ea00cb
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/direntry.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FAT Directory entry definitions.
+ */
+#ifndef __DIRENTRY_H
+#define __DIRENTRY_H
+
+#include <stdint.h>
+
+struct fat_sdirent {
+ char name[11]; /* DOS file name 8.3 */
+ uint8_t attr;
+ uint8_t Reserved;
+ uint8_t create_time_fine;
+ uint16_t create_time;
+ uint16_t create_date;
+ uint16_t access_date;
+ uint16_t cluster_hi;
+ uint16_t write_time;
+ uint16_t write_date;
+ uint16_t cluster_lo;
+ uint32_t size;
+} __attribute__((packed));
+
+
+#define FAT_LAST_LONG_ENTRY 0x40
+
+/* W95 long file name entries. Characters are in UTF-16. */
+struct fat_ldirent {
+ uint8_t ord;
+ uint16_t name1[5];
+ uint8_t attr;
+ uint8_t type;
+ uint8_t checksum;
+ uint16_t name2[6];
+ uint16_t cluster_lo;
+ uint16_t name3[2];
+} __attribute__((packed));
+
+uint8_t _fat_dirent_chksum(uint8_t *dosname);
+int _fat_dir_seek_empty(struct fat_file_handle *dir, int entries);
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/fat_core.c b/emb/pastilda/lib/libopenfat/fat_core.c
new file mode 100644
index 0000000..61f2143
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/fat_core.c
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FAT Filesystem core implementation
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "openfat.h"
+
+#include "openfat/blockdev.h"
+#include "openfat/leaccess.h"
+#include "bpb.h"
+#include "fat_core.h"
+
+/* Build time configuration */
+#define MAX_SECTOR_SIZE 512
+
+uint8_t _fat_sector_buf[MAX_SECTOR_SIZE];
+struct _fat_cache _fat_cache;
+
+int fat_vol_init(const struct block_device *dev, struct fat_vol_handle *h)
+{
+ struct bpb_common *bpb = (void *)&_fat_sector_buf;
+
+ memset(h, 0, sizeof(*h));
+ h->dev = dev;
+
+ FAT_GET_SECTOR(h, 0);
+
+ h->type = fat_type(bpb);
+ h->cluster_count = _bpb_cluster_count(bpb);
+ h->bytes_per_sector = __get_le16(&bpb->bytes_per_sector);
+ h->sectors_per_cluster = bpb->sectors_per_cluster;
+ h->first_data_sector = _bpb_first_data_sector(bpb);
+ h->reserved_sector_count = __get_le16(&bpb->reserved_sector_count);
+ h->num_fats = bpb->num_fats;
+ h->fat_size = _bpb_fat_size(bpb);
+ h->last_cluster_alloc = 2;
+ if(h->type == FAT_TYPE_FAT32) {
+ struct bpb_fat32 *bpb32 = (void *)&_fat_sector_buf;
+ h->fat32.root_cluster = __get_le32(&bpb32->root_cluster);
+ } else {
+ h->fat12_16.root_sector_count = _bpb_root_dir_sectors(bpb);
+ h->fat12_16.root_first_sector = _bpb_first_data_sector(bpb) -
+ h->fat12_16.root_sector_count;
+ }
+ _fat_file_root(h, &h->cwd);
+
+ return 0;
+}
+
+uint32_t _fat_get_next_cluster(const struct fat_vol_handle *h, uint32_t cluster)
+{
+ uint32_t offset;
+ uint32_t sector;
+
+ if(h->type == FAT_TYPE_FAT12)
+ offset = cluster + (cluster / 2);
+ else if(h->type == FAT_TYPE_FAT16)
+ offset = cluster * 2;
+ else if(h->type == FAT_TYPE_FAT32)
+ offset = cluster * 4;
+
+ sector = h->reserved_sector_count + (offset / h->bytes_per_sector);
+ offset %= h->bytes_per_sector;
+
+ FAT_GET_SECTOR(h, sector);
+
+ if(h->type == FAT_TYPE_FAT12) {
+ uint32_t next;
+ if(offset == (uint32_t)h->bytes_per_sector - 1) {
+ /* Fat entry is over sector boundary */
+ next = _fat_sector_buf[offset];
+ FAT_GET_SECTOR(h, sector + 1);
+ next += _fat_sector_buf[0] << 8;
+ } else {
+ next = __get_le16((uint16_t*)(_fat_sector_buf + offset));
+ }
+ if(cluster & 1)
+ return next >> 4;
+ else
+ return next & 0xFFF;
+ } else if(h->type == FAT_TYPE_FAT16) {
+ return __get_le16((uint16_t*)(_fat_sector_buf + offset));
+ } else if(h->type == FAT_TYPE_FAT32) {
+ return __get_le32((uint32_t*)(_fat_sector_buf + offset)) & 0x0FFFFFFF;
+ }
+ /* We shouldn't get here... */
+ return 0;
+}
+
+void _fat_file_root(struct fat_vol_handle *fat,
+ struct fat_file_handle *h)
+{
+ memset(h, 0, sizeof(*h));
+ h->fat = fat;
+
+ if(fat->type == FAT_TYPE_FAT32) {
+ h->first_cluster = fat->fat32.root_cluster;
+ } else {
+ /* FAT12/FAT16 root directory */
+ h->root_flag = 1;
+ h->first_cluster = fat->fat12_16.root_first_sector;
+ h->size = h->fat->fat12_16.root_sector_count * h->fat->bytes_per_sector;
+ }
+ h->cur_cluster = h->first_cluster;
+}
+
+void _fat_file_init(struct fat_vol_handle *fat,
+ const struct fat_sdirent *dirent,
+ struct fat_file_handle *h)
+{
+ memset(h, 0, sizeof(*h));
+ h->fat = fat;
+ h->first_cluster = ((uint32_t)__get_le16(&dirent->cluster_hi) << 16) |
+ __get_le16(&dirent->cluster_lo);
+ h->size = __get_le32(&dirent->size);
+ h->cur_cluster = h->first_cluster;
+}
+
+off_t fat_lseek(struct fat_file_handle *h, off_t offset, int whence)
+{
+ h->cur_cluster = h->first_cluster;
+
+ switch(whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += h->position;
+ break;
+ case SEEK_END:
+ offset += h->size;
+ break;
+ default:
+ return -1;
+ }
+
+ if(h->size && ((uint32_t)offset > h->size))
+ offset = h->size;
+
+ h->position = offset;
+
+ if(h->root_flag) { /* FAT12/16 root dir isn't a cluster chain */
+ return h->position;
+ }
+
+ /* Iterate over cluster chain to find cluster */
+ while(offset >= (h->fat->sectors_per_cluster * h->fat->bytes_per_sector)) {
+ h->cur_cluster = _fat_get_next_cluster(h->fat, h->cur_cluster);
+ offset -= h->fat->sectors_per_cluster * h->fat->bytes_per_sector;
+ }
+
+ return h->position;
+}
+
+void _fat_file_sector_offset(struct fat_file_handle *h, uint32_t *sector,
+ uint16_t *offset)
+{
+ if(h->root_flag) {
+ /* FAT12/FAT16 root directory */
+ *sector = h->cur_cluster +
+ (h->position / h->fat->bytes_per_sector);
+ } else {
+ *sector = fat_first_sector_of_cluster(h->fat, h->cur_cluster);
+ *sector += (h->position / h->fat->bytes_per_sector) %
+ h->fat->sectors_per_cluster;
+ }
+ *offset = h->position % h->fat->bytes_per_sector;
+}
+
+#define MIN(x, y) (((x) < (y))?(x):(y))
+int fat_read(struct fat_file_handle *h, void *buf, int size)
+{
+ int i;
+ uint32_t sector;
+ uint16_t offset;
+
+ _fat_file_sector_offset(h, &sector, &offset);
+
+ /* Don't read past end of file */
+ if(h->size && ((h->position + size) > h->size))
+ size = h->size - h->position;
+
+ for(i = 0; i < size; ) {
+ uint16_t chunk = MIN(h->fat->bytes_per_sector - offset, size - i);
+ FAT_GET_SECTOR(h->fat, sector);
+ memcpy(buf + i, _fat_sector_buf + offset, chunk);
+ h->position += chunk;
+ i += chunk;
+ if((h->position % h->fat->bytes_per_sector) != 0)
+ /* we didn't read until the end of the sector... */
+ break;
+ offset = 0;
+ sector++;
+ if(h->root_flag) /* FAT12/16 isn't a cluster chain */
+ continue;
+ if((sector % h->fat->sectors_per_cluster) == 0) {
+ /* Go to next cluster... */
+ h->cur_cluster = _fat_get_next_cluster(h->fat,
+ h->cur_cluster);
+ if(h->cur_cluster == fat_eoc(h->fat))
+ return i;
+ sector = fat_first_sector_of_cluster(h->fat,
+ h->cur_cluster);
+ }
+ }
+
+ return i;
+}
+
diff --git a/emb/pastilda/lib/libopenfat/fat_core.h b/emb/pastilda/lib/libopenfat/fat_core.h
new file mode 100644
index 0000000..4c681b3
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/fat_core.h
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FAT Filesystem core implementation, private interface
+ */
+#ifndef __FAT_CORE_H
+#define __FAT_CORE_H
+
+#include "bpb.h"
+#include "direntry.h"
+
+extern uint8_t _fat_sector_buf[];
+
+extern struct _fat_cache {
+ /* Working sector buffer, use _fat_sector_buf by default. */
+ uint8_t *buf;
+
+ /* Sector and block device for current contents of buf. */
+ const void *bldev;
+ uint32_t sector;
+
+ /* Non-zero if buffer is out-of-sync with the physical medium. */
+ uint8_t dirty;
+} _fat_cache;
+
+static inline uint32_t
+fat_eoc(const struct fat_vol_handle *fat)
+{
+ switch (fat->type) {
+ case FAT_TYPE_FAT12:
+ return 0x0FF8;
+ case FAT_TYPE_FAT16:
+ return 0xFFF8;
+ case FAT_TYPE_FAT32:
+ return 0x0FFFFFF8;
+ }
+ return -1;
+}
+
+static inline uint32_t
+fat_first_sector_of_cluster(const struct fat_vol_handle *fat, uint32_t n)
+{
+ return ((n - 2) * fat->sectors_per_cluster) + fat->first_data_sector;
+}
+
+uint32_t
+_fat_get_next_cluster(const struct fat_vol_handle *h, uint32_t cluster);
+
+void _fat_file_root(struct fat_vol_handle *fat, struct fat_file_handle *h);
+void _fat_file_init(struct fat_vol_handle *fat, const struct fat_sdirent *,
+ struct fat_file_handle *h);
+
+void _fat_file_sector_offset(struct fat_file_handle *h, uint32_t *sector,
+ uint16_t *offset);
+
+int _fat_dir_create_file(struct fat_vol_handle *vol, const char *name,
+ uint8_t attr, struct fat_file_handle *file);
+
+#define FAT_FLUSH_SECTOR() do {\
+ if(_fat_cache.dirty) \
+ if(block_write_sectors(_fat_cache.bldev, _fat_cache.sector, \
+ 1, _fat_sector_buf) != 1) \
+ return -EIO; \
+ _fat_cache.dirty = 0; \
+} while(0)
+
+#define FAT_GET_SECTOR(fat, sectorn) do {\
+ if((_fat_cache.bldev==(fat)->dev) && (_fat_cache.sector==(sectorn)))\
+ break; \
+\
+ FAT_FLUSH_SECTOR(); \
+\
+ _fat_cache.bldev = (fat)->dev; \
+ _fat_cache.sector = (sectorn); \
+\
+ if(block_read_sectors((fat)->dev, (sectorn), 1, _fat_sector_buf) != 1)\
+ return -EIO; \
+} while(0)
+
+#define FAT_PUT_SECTOR(fat, sectorn) do {\
+ if((_fat_cache.bldev!=(fat)->dev) || (_fat_cache.sector!=(sectorn)))\
+ FAT_FLUSH_SECTOR(); \
+\
+ _fat_cache.bldev = (fat)->dev; \
+ _fat_cache.sector = (sectorn); \
+ _fat_cache.dirty = 1; \
+} while(0)
+
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/mbr.c b/emb/pastilda/lib/libopenfat/mbr.c
new file mode 100644
index 0000000..6697746
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/mbr.c
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Master boot record.
+ */
+
+#include <stdint.h>
+
+#include "openfat/leaccess.h"
+#include "openfat/blockdev.h"
+#include "openfat/mbr.h"
+
+/* In fat_core.c */
+extern uint8_t _fat_sector_buf[];
+
+static int mbr_read_sectors(const struct block_device *dev,
+ uint32_t sector, uint32_t count, void *buf)
+{
+ struct block_mbr_partition *part = (void*)dev;
+
+ return block_read_sectors(part->whole,
+ part->first_lba + sector, count, buf);
+}
+
+static int mbr_write_sectors(const struct block_device *dev,
+ uint32_t sector, uint32_t count, const void *buf)
+{
+ struct block_mbr_partition *part = (void*)dev;
+
+ return block_write_sectors(part->whole,
+ part->first_lba + sector, count, buf);
+}
+
+int mbr_partition_init(struct block_mbr_partition *part,
+ struct block_device *whole, uint8_t part_index)
+{
+ struct mbr_partition *part_table = (void*)&_fat_sector_buf[446];
+ /* Read MBR from whole device */
+ if(block_read_sectors(whole, 0, 1, _fat_sector_buf) != 1)
+ return -1;
+
+ part->whole = whole;
+
+ part->first_lba = __get_le32(&part_table[part_index].first_lba);
+ part->sector_count = __get_le32(&part_table[part_index].sector_count);
+
+ part->bldev.get_sector_size = whole->get_sector_size;
+ part->bldev.read_sectors = mbr_read_sectors;
+ part->bldev.write_sectors = mbr_write_sectors;
+
+ return 0;
+}
+
+
diff --git a/emb/pastilda/lib/libopenfat/openfat.h b/emb/pastilda/lib/libopenfat/openfat.h
new file mode 100644
index 0000000..ec4b856
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/openfat.h
@@ -0,0 +1,220 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file openfat.h
+ * \brief FAT Filesystem implementation, public interface.
+ */
+
+#ifndef __OPENFAT_H
+#define __OPENFAT_H
+
+#include <stdint.h>
+
+#include <sys/stat.h>
+
+#include "openfat/blockdev.h"
+
+/* Forward declarations of private structures. */
+
+/** \brief Structure used internally for FAT volume state.
+ * Do not access directly. Structure has no public fields.
+ */
+typedef struct fat_vol_handle FatVol;
+
+/** \brief Structure used internally for FAT file state.
+ * Do not access directly. Structure has no public fields.
+ */
+typedef struct fat_file_handle FatFile;
+
+/** \brief Mount a FAT volume.
+ *
+ * Initialise a handle for access to a FAT filesystem on the specified
+ * block device.
+ * \param dev Pointer to block device to mount.
+ * \param vol Pointer to filesystem handle to initialise.
+ * \return 0 on success.
+ */
+int __attribute__((warn_unused_result))
+fat_vol_init(const struct block_device *dev, FatVol *vol);
+
+/** \brief Change current working directory.
+ * \param vol Pointer to FAT volume handle.
+ * \param name Directory name to change to. Relative to the current dir.
+ * \return 0 on success.
+ */
+int fat_chdir(FatVol *vol, const char *name);
+/** \brief Create a new directory.
+ * \param vol Pointer to FAT volume handle.
+ * \param name Directory name to create.
+ * \return 0 on success.
+ */
+int fat_mkdir(FatVol *vol, const char *name);
+/** \brief Remove an empty directory.
+ * \param vol Pointer to FAT volume handle.
+ * \param name Directory name to remove.
+ * \return 0 on success.
+ */
+int fat_rmdir(FatVol *vol, const char *name); /* TODO */
+
+/** \brief Open an existing file.
+ * The option O_ASYNC may be passed in flags to surpress the automatic
+ * updating of the files directory entry on writes. fat_file_sync() must be
+ * called explicitly to update it in this case.
+ *
+ * This function uses a ::dirent on the stack for iterating over the directory.
+ * This is a fairly large structure.
+ *
+ * \param vol Pointer to FAT volume handle.
+ * \param name File name in current directory to open.
+ * \param flags O_RDONLY, O_WRONLY, or O_RDWR. (currently not implemented)
+ * \param file Pointer to file handle to initialise.
+ * \return 0 on success.
+ */
+int __attribute__((warn_unused_result))
+fat_open(FatVol *vol, const char *name, int flags, FatFile *file);
+
+/** \brief Create a new file.
+ * \see fat_open()
+ *
+ * \param vol Pointer to FAT volume handle.
+ * \param name File name in current directory to create.
+ * \param flags O_RDONLY, O_WRONLY, or O_RDWR. (currently not implemented)
+ * \param file Pointer to file handle to initialise.
+ * \return 0 on success.
+ */
+int __attribute__((warn_unused_result))
+fat_create(FatVol *vol, const char *name, int flags, FatFile *file);
+
+#define O_ASYNC 020000
+/** \brief Update an open file's directory entry.
+ * This must be called explicitly if a file is opened with the flag O_ASYNC.
+ * In this case, updates to the directory entry are surpressed on writes to
+ * improve performance.
+ * \param file Pointer to file handle from which to read.
+ * \return 0 on success.
+ */
+int fat_file_sync(FatFile *h);
+
+/** \brief Read from an open file.
+ * \param file Pointer to file handle from which to read.
+ * \param buf Buffer into which to read.
+ * \param size Number of bytes to read.
+ * \return Number of bytes read on success, negative on error.
+ */
+int __attribute__((warn_unused_result))
+fat_read(FatFile *file, void *buf, int size);
+
+/** \brief Write to an open file.
+ * \param file Pointer to file handle into which to write.
+ * \param buf Buffer from which to write.
+ * \param size Number of bytes to write.
+ * \return Number of bytes written on success, negative on error.
+ */
+int __attribute__((warn_unused_result))
+fat_write(FatFile *file, const void *buf, int size);
+
+/** \brief Sets the position in an open file.
+ * \param file Pointer to file handle to change.
+ * \param offset Offset into target file.
+ * \param whence One of SEEK_SET, SEEK_CUR, SEEK_END. See Unix documentation.
+ * \return New file position on success, negative on error.
+ */
+off_t fat_lseek(FatFile *file, off_t offset, int whence);
+
+/** \brief Unlink/delete a file.
+ * \param vol Pointer to FAT volume handle.
+ * \param name Name of file in current directory to unlink.
+ * \return 0 on success.
+ */
+int fat_unlink(FatVol *vol, const char *name);
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+#define FAT_ATTR_LONG_NAME 0x0F
+
+/** \brief Public directory entry structure, returned by fat_readdir() */
+struct dirent {
+ char d_name[256]; /**< Long file name, POSIX standard. */
+ /* Non-standard */
+ uint8_t fat_attr; /**< FAT file attributes, non-standard */
+ char fat_sname[11]; /**< DOS short filename, non-standard */
+};
+
+/** \brief Read a directory entry.
+ * The dirent structure is filled in with the details of the next file in
+ * the directory stream pointed to by dir.
+ * \param dir Pointer to file handle for the directory to be read.
+ * \param ent Pointer to dirent structure for the read entry.
+ * \return 0 on success.
+ */
+int fat_readdir(FatFile *dir, struct dirent *ent);
+
+
+/* Everything below is private. Applications should not direcly access
+ * anything here.
+ */
+
+struct fat_file_handle {
+ struct fat_vol_handle *fat;
+ /* Fields from dir entry */
+ uint32_t size;
+ uint32_t first_cluster;
+ /* Internal state information */
+ uint32_t position;
+ uint32_t cur_cluster; /* This is used for sector on FAT12/16 root */
+ uint8_t root_flag; /* Flag to mark root directory on FAT12/16 */
+ int flags;
+ /* Reference to dirent */
+ uint32_t dirent_sector;
+ uint16_t dirent_offset;
+};
+
+struct fat_vol_handle {
+ const struct block_device *dev;
+ /* FAT type: 12, 16 or 32 */
+ int type;
+ /* Useful fields from BPB */
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sector_count;
+ uint8_t num_fats;
+ /* Fields calcuated from BPB */
+ uint32_t first_data_sector;
+ uint32_t cluster_count;
+ uint32_t fat_size;
+ union {
+ struct {
+ uint32_t root_cluster;
+ } fat32;
+ struct {
+ uint16_t root_sector_count;
+ uint16_t root_first_sector;
+ } fat12_16;
+ };
+ /* Internal state */
+ uint32_t last_cluster_alloc;
+ struct fat_file_handle cwd;
+};
+
+#endif
diff --git a/emb/pastilda/lib/libopenfat/openfat/blockdev.h b/emb/pastilda/lib/libopenfat/openfat/blockdev.h
new file mode 100644
index 0000000..ce8b15a
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/openfat/blockdev.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file blockdev.h
+ * \brief Block device abstraction.
+ * Must be implemented by application for a physical device.
+ */
+
+#ifndef __BLOCKDEV_H
+#define __BLOCKDEV_H
+
+#include <stdint.h>
+
+/** \brief Structure representing an abstract block device.
+ * This abstraction must be provided by the application.
+ */
+struct block_device {
+ /* Info about the device */
+ /** \brief Method to get sector size. */
+ uint16_t (*get_sector_size)(const struct block_device *dev);
+ /* ... more to be added as needed ... */
+
+ /* Actions on the device */
+ /** \brief Method to read sectors. */
+ int (*read_sectors)(const struct block_device *dev,
+ uint32_t sector, uint32_t count, void *buf);
+ /** \brief Method to write sectors. */
+ int (*write_sectors)(const struct block_device *dev,
+ uint32_t sector, uint32_t count, const void *buf);
+ /* ... more to be added as needed ... */
+
+ /* May be private fields here ... */
+};
+
+/* Convenient wrapper functions */
+static inline uint16_t
+block_get_sector_size(const struct block_device *dev)
+{
+ return dev->get_sector_size(dev);
+}
+
+/* Returns the number of sectors read or negative on error */
+static inline int __attribute__((warn_unused_result))
+block_read_sectors(const struct block_device *dev,
+ uint32_t sector, uint32_t count, void *buf)
+{
+ return dev->read_sectors(dev, sector, count, buf);
+}
+
+/* Returns the number of sectors written or negative on error */
+static inline int __attribute__((warn_unused_result))
+block_write_sectors(const struct block_device *dev,
+ uint32_t sector, uint32_t count, const void *buf)
+{
+ return dev->write_sectors(dev, sector, count, buf);
+}
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/openfat/leaccess.h b/emb/pastilda/lib/libopenfat/openfat/leaccess.h
new file mode 100644
index 0000000..6a48955
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/openfat/leaccess.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Macros for structure access. Host system may be little or big endian,
+ * and may not be capable of misaligned access. Always use these for
+ * access to the on-disk FAT structures.
+ */
+
+#ifndef __LEACCESS_H
+#define __LEACCESS_H
+
+#include <stdint.h>
+
+static inline uint16_t __get_le16(const uint16_t *p)
+{
+ return *(uint8_t *)p + (*((uint8_t *)p + 1) << 8);
+}
+
+static inline void __put_le16(uint16_t *p, uint16_t v)
+{
+ *(uint8_t *)p = v & 0xff;
+ *((uint8_t *)p + 1) = v >> 8;
+}
+
+static inline uint32_t __get_le32(const uint32_t *p)
+{
+ return __get_le16((uint16_t *)p) +
+ (uint32_t)(__get_le16((const uint16_t *)p + 1) << 16);
+}
+
+static inline void __put_le32(uint32_t *p, uint32_t v)
+{
+ __put_le16((uint16_t *)p, v & 0xffff);
+ __put_le16((uint16_t *)p + 1, v >> 16);
+}
+
+#ifdef __TEST__
+#include <stdio.h>
+#include <assert.h>
+int main(void)
+{
+ const char testdata[] = "\x01\x23\x45\x67";
+ printf("%08X\n", __get_le32((uint32_t *)testdata));
+ assert(__get_le32((uint32_t *)testdata) == 0x67452301);
+ return 0;
+}
+#endif
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/openfat/mbr.h b/emb/pastilda/lib/libopenfat/openfat/mbr.h
new file mode 100644
index 0000000..a9f41f9
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/openfat/mbr.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file mbr.h
+ * \brief PC Disk Partition Table implementation.
+ * This module provides interpretation of the PC Master Boot Record
+ * partition table, and provides a block device implementation for
+ * partitions given an implementation for the whole disk using wrapper
+ * functions.
+ */
+
+#ifndef __MBR_H
+#define __MBR_H
+
+#include <stdint.h>
+
+#include "blockdev.h"
+
+struct mbr_partition {
+ uint8_t bootable;
+ uint8_t first_chs[3];
+ uint8_t type;
+ uint8_t last_chs[3];
+ uint32_t first_lba;
+ uint32_t sector_count;
+} __attribute__((packed));
+
+/** \brief Structure representing block device for a PC disk partition.
+ * Don't access directly. No public fields. */
+struct block_mbr_partition {
+ struct block_device bldev;
+ struct block_device *whole;
+ uint32_t first_lba;
+ uint32_t sector_count;
+};
+
+/** \brief Initialise a partition block device.
+ * \param part Pointer to partition block device to initialize.
+ * \param whole Pointer to block device for whole media.
+ * \param part_index Partition index (0-3).
+ * \return 0 on success.
+ */
+int mbr_partition_init(struct block_mbr_partition *part,
+ struct block_device *whole, uint8_t part_index);
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/openfat/unixlike.h b/emb/pastilda/lib/libopenfat/openfat/unixlike.h
new file mode 100644
index 0000000..cfba7cd
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/openfat/unixlike.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Unix-like API for FAT filesystem access.
+ */
+
+#ifndef __UNIXLIKE_H
+#define __UNIXLIKE_H
+
+#include <openfat.h>
+
+#include <stdlib.h>
+
+FatVol * ufat_mount(struct block_device *dev);
+static inline void ufat_umount(FatVol *vol) { free(vol); }
+
+FatFile * ufat_open(FatVol *vol, const char *path, int flags);
+static inline void ufat_close(FatFile *file) { free(file); }
+
+int ufat_stat(FatFile *file, struct stat *stat);
+
+#define ufat_read fat_read
+#define ufat_write fat_write
+
+#define ufat_chdir fat_chdir
+#define ufat_mkdir fat_mkdir
+
+#endif
+
diff --git a/emb/pastilda/lib/libopenfat/unixlike.c b/emb/pastilda/lib/libopenfat/unixlike.c
new file mode 100644
index 0000000..ec2e908
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/unixlike.c
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "openfat.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "openfat/blockdev.h"
+#include "fat_core.h"
+#include "direntry.h"
+
+struct fat_vol_handle *
+ufat_mount(struct block_device *dev)
+{
+ struct fat_vol_handle *vol = malloc(sizeof(*vol));
+
+ if(fat_vol_init(dev, vol)) {
+ free(vol);
+ return NULL;
+ }
+
+ return vol;
+}
+
+struct fat_file_handle *
+ufat_open(struct fat_vol_handle *fat, const char *path, int flags)
+{
+ struct fat_file_handle oldcwd;
+
+ if(!path || (path[0] == 0))
+ return NULL;
+
+ struct fat_file_handle *h = malloc(sizeof(*h));
+
+ if(path[0] == '/') {
+ _fat_file_root(fat, h);
+ path++;
+ } else {
+ memcpy(h, &fat->cwd, sizeof(*h));
+ }
+
+ memcpy(&oldcwd, &fat->cwd, sizeof(oldcwd));
+ while(path && *path) {
+ memcpy(&fat->cwd, h, sizeof(*h));
+ if(fat_open(fat, path, flags, h)) {
+ free(h);
+ memcpy(&fat->cwd, &oldcwd, sizeof(oldcwd));
+ return NULL;
+ }
+ path = strchr(path, '/');
+ if(path) path++;
+ };
+
+ memcpy(&fat->cwd, &oldcwd, sizeof(oldcwd));
+
+ return h;
+}
+
+int ufat_stat(struct fat_file_handle *h, struct stat *st)
+{
+ struct fat_sdirent *fatent;
+
+ memset(st, 0, sizeof(*st));
+
+ if(h->dirent_sector == 0) {
+ /* Root directory */
+ st->st_mode = S_IFDIR;
+ return 0;
+ }
+
+ /* Read direntry sector */
+ if(block_read_sectors(h->fat->dev, h->dirent_sector, 1, _fat_sector_buf) != 1)
+ return -1;
+ fatent = (void*)&_fat_sector_buf[h->dirent_offset];
+
+ /* TODO: Fill in timestamps */
+
+ if(fatent->attr & FAT_ATTR_DIRECTORY) {
+ st->st_mode = S_IFDIR;
+ } else {
+ st->st_size = __get_le32(&fatent->size);
+ }
+
+ return 0;
+}
+
diff --git a/emb/pastilda/lib/libopenfat/write.c b/emb/pastilda/lib/libopenfat/write.c
new file mode 100644
index 0000000..6e9e62f
--- /dev/null
+++ b/emb/pastilda/lib/libopenfat/write.c
@@ -0,0 +1,453 @@
+/*
+ * This file is part of the openfat project.
+ *
+ * Copyright (C) 2011 Department of Physics, University of Otago
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FAT Filesystem write support implementation
+ */
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "openfat.h"
+
+#include "fat_core.h"
+
+static uint32_t fat_find_free_cluster(struct fat_vol_handle *h)
+{
+ uint32_t i;
+
+ for(i = h->last_cluster_alloc; i < h->cluster_count; i++) {
+ if(_fat_get_next_cluster(h, i) == 0) {
+ h->last_cluster_alloc = i;
+ return i;
+ }
+ }
+
+ for(i = 2; i < h->last_cluster_alloc; i++) {
+ if(_fat_get_next_cluster(h, i) == 0) {
+ h->last_cluster_alloc = i;
+ return i;
+ }
+ }
+
+ return 0; /* No free clusters */
+}
+
+static int
+fat32_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
+ uint32_t cluster, uint32_t next)
+{
+ uint32_t offset = cluster * 4;
+ uint32_t sector;
+
+ sector = h->reserved_sector_count + (fat * h->fat_size) +
+ (offset / h->bytes_per_sector);
+ offset %= h->bytes_per_sector;
+
+ FAT_GET_SECTOR(h, sector);
+
+ /* Preserve high nybble */
+ next &= 0x0FFFFFFF;
+ next |= __get_le32((uint32_t*)(_fat_sector_buf + offset)) & 0xF0000000;
+ __put_le32((uint32_t*)(_fat_sector_buf + offset), next);
+
+ FAT_PUT_SECTOR(h, sector);
+
+ return 0;
+}
+
+static int
+fat16_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
+ uint16_t cluster, uint16_t next)
+{
+ uint32_t offset = cluster * 2;
+ uint32_t sector;
+
+ sector = h->reserved_sector_count + (fat * h->fat_size) +
+ (offset / h->bytes_per_sector);
+ offset %= h->bytes_per_sector;
+
+ FAT_GET_SECTOR(h, sector);
+ __put_le16((uint16_t*)(_fat_sector_buf + offset), next);
+ FAT_PUT_SECTOR(h, sector);
+
+ return 0;
+}
+
+static int
+fat12_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
+ uint16_t cluster, uint16_t next)
+{
+ uint32_t offset = cluster + (cluster / 2);
+ uint32_t sector;
+ sector = h->reserved_sector_count + (fat * h->fat_size) +
+ (offset / h->bytes_per_sector);
+ offset %= h->bytes_per_sector;
+
+ FAT_GET_SECTOR(h, sector);
+ if(offset == (uint32_t)h->bytes_per_sector - 1) {
+ if(cluster & 1) {
+ next <<= 4;
+ _fat_sector_buf[offset] &= 0x0F;
+ _fat_sector_buf[offset] |= next & 0xF0;
+ FAT_PUT_SECTOR(h, sector);
+ sector++;
+ FAT_GET_SECTOR(h, sector);
+ _fat_sector_buf[0] = next >> 8;
+ } else {
+ _fat_sector_buf[offset] = next & 0xFF;
+ FAT_PUT_SECTOR(h, sector);
+ sector++;
+ FAT_GET_SECTOR(h, sector);
+ _fat_sector_buf[0] &= 0xF0;
+ _fat_sector_buf[0] |= (next >> 8) & 0x0F;
+ }
+ } else {
+ if(cluster & 1) {
+ next <<= 4;
+ next |= __get_le16((uint16_t*)(_fat_sector_buf + offset)) & 0xF;
+ } else {
+ next &= 0x0FFF;
+ next |= __get_le16((uint16_t*)(_fat_sector_buf + offset)) & 0xF000;
+ }
+ __put_le16((uint16_t*)(_fat_sector_buf + offset), next);
+ }
+ FAT_PUT_SECTOR(h, sector);
+
+ return 0;
+}
+
+static int
+fat_set_next_cluster(const struct fat_vol_handle *h,
+ uint32_t cluster, uint32_t next)
+{
+ int ret = 0;
+ for(int i = 0; i < h->num_fats; i++) {
+ switch(h->type) {
+ case FAT_TYPE_FAT12:
+ ret |= fat12_set_next_cluster(h, i, cluster, next);
+ break;
+ case FAT_TYPE_FAT16:
+ ret |= fat16_set_next_cluster(h, i, cluster, next);
+ break;
+ case FAT_TYPE_FAT32:
+ ret |= fat32_set_next_cluster(h, i, cluster, next);
+ break;
+ }
+ }
+ return ret;
+}
+
+static int32_t fat_alloc_next_cluster(struct fat_vol_handle *h,
+ uint32_t cluster, int clear)
+{
+ /* Return next if already allocated */
+ uint32_t next = _fat_get_next_cluster(h, cluster);
+
+ if(next != fat_eoc(h))
+ return next;
+
+ /* Find free cluster to link to */
+ next = fat_find_free_cluster(h);
+
+ if(!next) /* No more free clusters */
+ return 0;
+
+ /* Write end of chain marker in new cluster */
+ fat_set_next_cluster(h, next, fat_eoc(h));
+ /* Add new cluster to chain */
+ fat_set_next_cluster(h, cluster, next);
+
+ if(clear) {
+ /* Zero new cluster */
+ uint32_t sector = fat_first_sector_of_cluster(
+ h, next);
+ FAT_FLUSH_SECTOR();
+ memset(_fat_sector_buf, 0, h->bytes_per_sector);
+ for(int i = 0; i < h->sectors_per_cluster; i++) {
+ /* How do we report failure here?
+ * The cluster has already been allocated.
+ */
+ int discard = block_write_sectors(h->dev, sector + i, 1,
+ _fat_sector_buf);
+ (void)discard;
+ }
+ }
+
+ return next;
+}
+
+int fat_file_sync(struct fat_file_handle *h)
+{
+ struct fat_sdirent *dirent;
+ /* Update directory entry with new size */
+ FAT_GET_SECTOR(h->fat, h->dirent_sector);
+ dirent = (void*)&_fat_sector_buf[h->dirent_offset];
+ __put_le32(&dirent->size, h->size);
+ __put_le16(&dirent->cluster_hi, h->first_cluster >> 16);
+ __put_le16(&dirent->cluster_lo, h->first_cluster & 0xFFFF);
+ FAT_PUT_SECTOR(h->fat, h->dirent_sector);
+ FAT_FLUSH_SECTOR();
+ return 0;
+}
+
+#define MIN(x, y) (((x) < (y))?(x):(y))
+int fat_write(struct fat_file_handle *h, const void *buf, int size)
+{
+ int i;
+ uint32_t sector;
+ uint16_t offset;
+
+ if(!h->cur_cluster && size) {
+ /* File was empty, allocate first cluster. */
+ h->first_cluster = fat_find_free_cluster(h->fat);
+ if(!h->first_cluster)
+ return 0;
+ h->cur_cluster = h->first_cluster;
+ /* Write end of chain marker in new cluster */
+ fat_set_next_cluster(h->fat, h->cur_cluster, fat_eoc(h->fat));
+ /* Directory entry will be updated with size after the
+ * file write is done.
+ */
+ }
+
+ /* Don't write past end of FAT12/FAT16 root directory! */
+ if(h->root_flag && ((h->position + size) > h->size))
+ size = h->size - h->position;
+
+ _fat_file_sector_offset(h, &sector, &offset);
+
+ for(i = 0; i < size; ) {
+ uint16_t chunk = MIN(h->fat->bytes_per_sector - offset,
+ size - i);
+ if(chunk < h->fat->bytes_per_sector)
+ FAT_GET_SECTOR(h->fat, sector);
+ else
+ FAT_FLUSH_SECTOR();
+
+ memcpy(_fat_sector_buf + offset, buf + i, chunk);
+ FAT_PUT_SECTOR(h->fat, sector);
+ h->position += chunk;
+ i += chunk;
+ if((h->position % h->fat->bytes_per_sector) != 0)
+ /* we didn't write until the end of the sector... */
+ break;
+ offset = 0;
+ sector++;
+ if(h->root_flag) /* FAT12/16 isn't a cluster chain */
+ continue;
+ if((sector % h->fat->sectors_per_cluster) == 0) {
+ /* Go to next cluster... */
+ uint32_t next_cluster = fat_alloc_next_cluster(h->fat,
+ h->cur_cluster, h->size == 0);
+ if(!next_cluster)
+ break;
+ h->cur_cluster = next_cluster;
+ sector = fat_first_sector_of_cluster(h->fat,
+ h->cur_cluster);
+ }
+ }
+
+ if(h->dirent_sector && (h->position > h->size)) {
+ /* Update directory entry with new size */
+ h->size = h->position;
+ if(!(h->flags & O_ASYNC))
+ fat_file_sync(h);
+ }
+
+ return i;
+}
+
+static int fat_chain_unlink(const struct fat_vol_handle *vol, uint32_t cluster)
+{
+ int ret = 0;
+ while(cluster && (cluster != fat_eoc(vol))) {
+ uint32_t next = _fat_get_next_cluster(vol, cluster);
+ ret |= fat_set_next_cluster(vol, cluster, 0);
+ cluster = next;
+ }
+ return ret;
+}
+
+int fat_unlink(struct fat_vol_handle *vol, const char *name)
+{
+ struct fat_file_handle h;
+ int ret;
+
+ ret = fat_open(vol, name, 0, &h);
+ if(ret)
+ return ret;
+
+ /* Don't try to unlink directories, use fat_rmdir() instead. */
+ if(!h.dirent_sector)
+ return -EISDIR;
+
+ /* Free up cluster chain */
+ fat_chain_unlink(vol, h.first_cluster);
+
+ /* Mark directory entry as deleted */
+ FAT_GET_SECTOR(vol, h.dirent_sector);
+ _fat_sector_buf[h.dirent_offset] = 0xE5;
+ FAT_PUT_SECTOR(vol, h.dirent_sector);
+
+ /* FIXME: Remove long name entries. */
+
+ return 0;
+}
+
+/* Build a short name for a long name. n is used if name is too long. */
+static void build_short_name(uint8_t *sname, const char *name, int n)
+{
+ int i, j;
+
+ memset(sname, ' ', 11);
+ for(i = 0; (i < 8) && name[i] && (name[i] != '.'); i++)
+ sname[i] = toupper(name[i]);
+
+ char *suffix = strrchr(name, '.');
+ if(suffix) for(j = 1; (j < 4) && suffix[j]; j++)
+ sname[j+7] = toupper(suffix[j]);
+
+ if(((i == 8) && (name[i] != '.')) ||
+ ((suffix - name) != i)) {
+ if(i > 6)
+ i = 6;
+ sname[i] = '~';
+ sname[i+1] = '0' + (n % 10);
+ }
+}
+
+/* Create a new zero-length file */
+int _fat_dir_create_file(struct fat_vol_handle *vol, const char *name,
+ uint8_t attr, struct fat_file_handle *file)
+{
+ /* Check if file already exists */
+ if(!fat_open(vol, name, 0, file))
+ return -1; /* File exists */
+
+ /* Attempt to construct a short name for the file */
+ uint8_t sname[12];
+ sname[11] = 0; /* fat_open() needs terminating null */
+ for(int i = 1; i < 10; i++) {
+ build_short_name(sname, name, i);
+ if(fat_open(vol, (char*)sname, 0, file))
+ break; /* We have a winner */
+ sname[0] = ' ';
+ }
+
+ if(sname[0] == ' ')
+ return -1; /* Couldn't find a short name */
+
+ /* Find usable space in parent directory */
+ _fat_dir_seek_empty(&vol->cwd, (strlen(name) / 13) + 2);
+
+ /* Create long name directory entries */
+ struct fat_ldirent ld;
+ int last = 1;
+ memset(&ld, 0, sizeof(ld));
+ ld.attr = FAT_ATTR_LONG_NAME;
+ for(int i = strlen(name) / 13; i >= 0; i--) {
+ ld.ord = i + 1;
+ if(last) {
+ ld.ord |= FAT_LAST_LONG_ENTRY;
+ last = 0;
+ }
+ int j;
+ for(j = 0; j < 5; j++)
+ __put_le16(&ld.name1[j], name[i*13 + j]);
+ for(j = 0; j < 6; j++)
+ __put_le16(&ld.name2[j], name[i*13 + j + 5]);
+ for(j = 0; j < 2; j++)
+ __put_le16(&ld.name3[j], name[i*13 + j + 11]);
+ ld.checksum = _fat_dirent_chksum(sname);
+ if(fat_write(&vol->cwd, &ld, sizeof(ld)) != sizeof(ld))
+ return -1;
+ }
+
+ /* Create short name entry */
+ struct fat_sdirent fatent;
+ memset(&fatent, 0, sizeof(fatent));
+ fatent.attr = attr;
+ memcpy(&fatent.name, sname, 11);
+ /* TODO: Insert timestamp */
+ if(attr == FAT_ATTR_DIRECTORY) {
+ /* Allocate a cluster for directories */
+ uint32_t cluster = fat_find_free_cluster(vol);
+ if(!cluster)
+ return -1;
+ fat_set_next_cluster(vol, cluster, fat_eoc(vol));
+ __put_le16(&fatent.cluster_hi, cluster >> 16);
+ __put_le16(&fatent.cluster_lo, cluster & 0xFFFF);
+ }
+ if(fat_write(&vol->cwd, &fatent, sizeof(fatent)) != sizeof(fatent))
+ return -1;
+
+ return fat_open(vol, name, 0, file);
+}
+
+int fat_mkdir(struct fat_vol_handle *vol, const char *name)
+{
+ int ret;
+ struct fat_file_handle dir;
+ struct fat_sdirent fatent;
+ ret = _fat_dir_create_file(vol, name, FAT_ATTR_DIRECTORY, &dir);
+ if(ret)
+ return ret;
+
+ FAT_FLUSH_SECTOR();
+ /* Clear out cluster */
+ memset(_fat_sector_buf, 0, vol->bytes_per_sector);
+ uint32_t sector = fat_first_sector_of_cluster(vol, dir.first_cluster);
+ for(int i = 0; i < vol->sectors_per_cluster; i++)
+ FAT_PUT_SECTOR(vol, sector + i);
+
+ memset(&fatent, 0, sizeof(fatent));
+ fatent.attr = FAT_ATTR_DIRECTORY;
+ memset(fatent.name, ' ', 11);
+
+ /* Create '.' entry */
+ fatent.name[0] = '.';
+ __put_le16(&fatent.cluster_hi, dir.first_cluster >> 16);
+ __put_le16(&fatent.cluster_lo, dir.first_cluster & 0xFFFF);
+ ret = fat_write(&dir, &fatent, sizeof(fatent));
+ if(ret < 0)
+ return ret;
+
+ /* Create '..' entry */
+ fatent.name[1] = '.';
+ if((!vol->cwd.root_flag) &&
+ (vol->fat32.root_cluster != vol->cwd.first_cluster)) {
+ __put_le16(&fatent.cluster_hi, vol->cwd.first_cluster >> 16);
+ __put_le16(&fatent.cluster_lo, vol->cwd.first_cluster & 0xFFFF);
+ } else {
+ fatent.cluster_hi = 0;
+ fatent.cluster_lo = 0;
+ }
+ ret = fat_write(&dir, &fatent, sizeof(fatent));
+ return (ret < 0) ? ret : 0;
+}
+
+int fat_create(struct fat_vol_handle *vol, const char *name, int flags,
+ struct fat_file_handle *file)
+{
+ int ret = _fat_dir_create_file(vol, name, FAT_ATTR_ARCHIVE, file);
+ file->flags = flags;
+ return ret;
+}
+
diff --git a/emb/pastilda/main.cpp b/emb/pastilda/main.cpp
index 3268a72..27a191d 100644
--- a/emb/pastilda/main.cpp
+++ b/emb/pastilda/main.cpp
@@ -2,17 +2,8 @@
#include "stdio.h"
using namespace Application;
-#ifdef DEBUG
- #define DEBUG_PRINT(x) printf(x)
-#else
- #define DEBUG_PRINT(x) do {} while (0)
-#endif
-
-extern "C" void initialise_monitor_handles(void);
-
int main()
{
- //initialise_monitor_handles();
App *app = new App();
while(1) {
app->process();
diff --git a/emb/pastilda/stm32f407vg.ld b/emb/pastilda/stm32f405rg.ld
index c5e1bf8..c5e1bf8 100644
--- a/emb/pastilda/stm32f407vg.ld
+++ b/emb/pastilda/stm32f405rg.ld
diff --git a/emb/pastilda/hw/usb_device/usbd_composite.cpp b/emb/pastilda/usb/usb_device/usbd_composite.cpp
index aac38db..6136594 100644
--- a/emb/pastilda/hw/usb_device/usbd_composite.cpp
+++ b/emb/pastilda/usb/usb_device/usbd_composite.cpp
@@ -19,12 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "usbd_composite.h"
+#include <usb/usb_device/usbd_composite.h>
using namespace GPIO_CPP_Extension;
USB_composite *usb_pointer;
-USB_composite::USB_composite()
+USB_composite::USB_composite(const uint32_t block_count,
+ int (*read_block)(uint32_t lba, uint8_t *copy_to),
+ int (*write_block)(uint32_t lba, const uint8_t *copy_from))
{
usb_pointer = this;
descriptors = new UsbCompositeDescriptors();
@@ -38,17 +40,15 @@ USB_composite::USB_composite()
uf_p.set_af(AF_Number::AF10);
uf_m.set_af(AF_Number::AF10);
- my_usb_device = usbd_init(&otgfs_usb_driver, &(descriptors->dev),
- &(descriptors->config_descr), (const char**)descriptors->usb_strings, 3,
+ my_usb_device = usbd_init(&otgfs_usb_driver, &(UsbCompositeDescriptors::dev),
+ &(UsbCompositeDescriptors::config_descr), (const char**)UsbCompositeDescriptors::usb_strings, 3,
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(my_usb_device, USB_set_config_callback);
nvic_enable_irq(NVIC_OTG_FS_IRQ);
- ramdisk_init();
-
usb_msc_init(my_usb_device, Endpoint::E_MASS_STORAGE_IN, 64, Endpoint::E_MASS_STORAGE_OUT, 64,
- "ThirdPin", "Pastilda", "0.00", ramdisk_blocks(), ramdisk_read, ramdisk_write);
+ "ThirdPin", "Pastilda", "0.00", block_count, read_block, write_block);
}
void USB_composite::usb_send_packet(const void *buf, int len)
@@ -61,6 +61,15 @@ void USB_OTG_IRQ()
usbd_poll(usb_pointer->my_usb_device);
}
+void USB_composite::hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
+{
+ (void)wValue;
+ (void)usbd_dev;
+
+ usbd_ep_setup(usbd_dev, Endpoint::E_KEYBOARD, USB_ENDPOINT_ATTR_INTERRUPT, 8, 0);
+ usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_RECIPIENT, USB_control_callback );
+}
+
int USB_composite::hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
@@ -145,7 +154,7 @@ int USB_control_callback(usbd_device *usbd_dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
usbd_control_complete_callback *complete)
{
- return( usb_pointer->hid_control_request(usbd_dev, req, buf, len, complete));
+ return(usb_pointer->hid_control_request(usbd_dev, req, buf, len, complete));
}
diff --git a/emb/pastilda/hw/usb_device/usbd_composite.h b/emb/pastilda/usb/usb_device/usbd_composite.h
index 0fa239f..ac83f3b 100644
--- a/emb/pastilda/hw/usb_device/usbd_composite.h
+++ b/emb/pastilda/usb/usb_device/usbd_composite.h
@@ -19,13 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef USB_MSC_H
-#define USB_MSC_H
+#ifndef USB_COMPOSITE_H
+#define USB_COMPOSITE_H
-extern "C"
-{
-#include "ramdisk.h"
-}
#include "usbd_composite_desc.h"
#include "systick_ext.h"
#include "gpio_ext.h"
@@ -56,25 +52,15 @@ public:
uint8_t usb_ready = 0;
usbd_device *my_usb_device;
- USB_composite();
+ USB_composite(const uint32_t block_count,
+ int (*read_block)(uint32_t lba, uint8_t *copy_to),
+ int (*write_block)(uint32_t lba, const uint8_t *copy_from));
void usb_send_packet(const void *buf, int len);
- void usb_poll()
- {
- usbd_poll(my_usb_device);
- }
-
int hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
-
- void hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
- {
- (void)wValue;
- (void)usbd_dev;
+ void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
- usbd_ep_setup(usbd_dev, Endpoint::E_KEYBOARD, USB_ENDPOINT_ATTR_INTERRUPT, 8, 0);
- usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_RECIPIENT, USB_control_callback );
- }
+ void hid_set_config(usbd_device *usbd_dev, uint16_t wValue);
};
#endif
diff --git a/emb/pastilda/hw/usb_device/usbd_composite_desc.cpp b/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp
index daf025a..c1018cc 100644
--- a/emb/pastilda/hw/usb_device/usbd_composite_desc.cpp
+++ b/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "usbd_composite_desc.h"
+#include <usb/usb_device/usbd_composite_desc.h>
constexpr uint8_t UsbCompositeDescriptors::keyboard_report_descriptor[];
constexpr UsbCompositeDescriptors::type_hid_function UsbCompositeDescriptors::keyboard_hid_function;
diff --git a/emb/pastilda/hw/usb_device/usbd_composite_desc.h b/emb/pastilda/usb/usb_device/usbd_composite_desc.h
index 2c09aa0..2c09aa0 100644
--- a/emb/pastilda/hw/usb_device/usbd_composite_desc.h
+++ b/emb/pastilda/usb/usb_device/usbd_composite_desc.h
diff --git a/emb/pastilda/hw/usb_host/usbh_host.cpp b/emb/pastilda/usb/usb_host/usbh_host.cpp
index b38a7e4..4a8f559 100644
--- a/emb/pastilda/hw/usb_host/usbh_host.cpp
+++ b/emb/pastilda/usb/usb_host/usbh_host.cpp
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "usbh_host.h"
+#include <usb/usb_host/usbh_host.h>
constexpr hid_kbd_config_t USB_host::kbd_config;
constexpr usbh_dev_driver_t* USB_host::device_drivers[];
diff --git a/emb/pastilda/hw/usb_host/usbh_host.h b/emb/pastilda/usb/usb_host/usbh_host.h
index 868026b..868026b 100644
--- a/emb/pastilda/hw/usb_host/usbh_host.h
+++ b/emb/pastilda/usb/usb_host/usbh_host.h