* Patch by Daniel Engström, 13 Nov 2002:
  Add support for i386 architecture and AMD SC520 board

* Patch by Pierre Aubert, 12 Nov 2002:
  Add support for DOS filesystem and booting from DOS floppy disk
diff --git a/fs/fdos/Makefile b/fs/fdos/Makefile
new file mode 100644
index 0000000..af0fff1
--- /dev/null
+++ b/fs/fdos/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2002
+# Stäubli Faverges - <www.staubli.com>
+# Pierre AUBERT  p.aubert@staubli.com
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= libfdos.a
+
+AOBJS	=
+COBJS	= fat.o vfat.o dev.o fdos.o fs.o subdir.o 
+OBJS	= $(AOBJS) $(COBJS)
+
+#CPPFLAGS +=
+
+all:	$(LIB) $(AOBJS)
+
+$(LIB):	.depend $(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+
+#########################################################################
+
+.depend:	Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/fs/fdos/dev.c b/fs/fdos/dev.c
new file mode 100644
index 0000000..f38d07d
--- /dev/null
+++ b/fs/fdos/dev.c
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#include "dos.h"
+#include "fdos.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#define NB_HEADS        2
+#define NB_TRACKS       80
+#define NB_SECTORS      18
+
+
+static int lastwhere;
+
+/*-----------------------------------------------------------------------------
+ * dev_open -- 
+ *-----------------------------------------------------------------------------
+ */
+int dev_open (void)
+{
+    lastwhere = 0;
+    return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * dev_read -- len and where are sectors number
+ *-----------------------------------------------------------------------------
+ */
+int dev_read (void *buffer, int where, int len)
+{
+    PRINTF ("dev_read (len = %d, where = %d)\n", len, where);
+
+    /* Si on ne desire pas lire a la position courante, il faut un seek      */
+    if (where != lastwhere) {
+        if (!fdc_fdos_seek (where)) {
+            PRINTF ("seek error in dev_read");
+            lastwhere = -1;
+            return (-1);
+        }
+    }
+    
+    if (!fdc_fdos_read (buffer, len)) {
+        PRINTF ("read error\n");
+        lastwhere = -1;
+        return (-1);
+    }
+    lastwhere = where + len;
+    return (0);
+}
+/*-----------------------------------------------------------------------------
+ * check_dev -- verify the diskette format
+ *-----------------------------------------------------------------------------
+ */
+int check_dev (BootSector_t *boot, Fs_t *fs)
+{
+    unsigned int heads, sectors, tracks;
+    int BootP, Infp0, InfpX, InfTm;
+    int sect_per_track;
+
+    /* Display Boot header                                                   */
+    PRINTF ("Jump to boot code                  0x%02x 0x%02x 0x%02x\n",
+            boot -> jump [0], boot -> jump [1], boot -> jump[2]);
+    PRINTF ("OEM name & version                 '%*.*s'\n",
+            BANNER_LG, BANNER_LG, boot -> banner );
+    PRINTF ("Bytes per sector hopefully 512     %d\n",
+            __le16_to_cpu (boot -> secsiz));
+    PRINTF ("Cluster size in sectors            %d\n",
+            boot -> clsiz);
+    PRINTF ("Number of reserved (boot) sectors  %d\n",
+            __le16_to_cpu (boot -> nrsvsect));
+    PRINTF ("Number of FAT tables hopefully 2   %d\n",
+            boot -> nfat);
+    PRINTF ("Number of directory slots          %d\n",
+            __le16_to_cpu (boot -> dirents));
+    PRINTF ("Total sectors on disk              %d\n",
+            __le16_to_cpu (boot -> psect));
+    PRINTF ("Media descriptor=first byte of FAT %d\n",
+            boot -> descr);
+    PRINTF ("Sectors in FAT                     %d\n",
+            __le16_to_cpu (boot -> fatlen));
+    PRINTF ("Sectors/track                      %d\n",
+            __le16_to_cpu (boot -> nsect));
+    PRINTF ("Heads                              %d\n",
+            __le16_to_cpu (boot -> nheads));
+    PRINTF ("number of hidden sectors           %d\n",
+            __le32_to_cpu (boot -> nhs));
+    PRINTF ("big total sectors                  %d\n",
+            __le32_to_cpu (boot -> bigsect));
+    PRINTF ("physical drive ?                   %d\n",
+            boot -> physdrive);
+    PRINTF ("reserved                           %d\n",
+            boot -> reserved);
+    PRINTF ("dos > 4.0 diskette                 %d\n",
+            boot -> dos4);
+    PRINTF ("serial number                      %d\n",
+            __le32_to_cpu (boot -> serial));
+    PRINTF ("disk label                         %*.*s\n",
+            LABEL_LG, LABEL_LG, boot -> label);
+    PRINTF ("FAT type                           %8.8s\n",
+            boot -> fat_type);
+    PRINTF ("reserved by 2M                     %d\n",
+            boot -> res_2m);
+    PRINTF ("2M checksum (not used)             %d\n",
+            boot -> CheckSum);
+    PRINTF ("2MF format version                 %d\n",
+            boot -> fmt_2mf);
+    PRINTF ("1 if write track after format      %d\n",
+            boot -> wt);
+    PRINTF ("data transfer rate on track 0      %d\n",
+            boot -> rate_0);
+    PRINTF ("data transfer rate on track<>0     %d\n",
+            boot -> rate_any);
+    PRINTF ("offset to boot program             %d\n",
+            __le16_to_cpu (boot -> BootP));
+    PRINTF ("T1: information for track 0        %d\n",
+            __le16_to_cpu (boot -> Infp0));
+    PRINTF ("T2: information for track<>0       %d\n",
+            __le16_to_cpu (boot -> InfpX));
+    PRINTF ("T3: track sectors size table       %d\n",
+            __le16_to_cpu (boot -> InfTm));
+    PRINTF ("Format date                        0x%04x\n",
+            __le16_to_cpu (boot -> DateF));
+    PRINTF ("Format time                        0x%04x\n",
+            __le16_to_cpu (boot -> TimeF));
+    
+
+    /* informations are extracted from boot sector                           */
+    heads = __le16_to_cpu (boot -> nheads);
+    sectors = __le16_to_cpu (boot -> nsect);
+    fs -> tot_sectors = __le32_to_cpu (boot -> bigsect);
+    if (__le16_to_cpu (boot -> psect) != 0) {
+        fs -> tot_sectors = __le16_to_cpu (boot -> psect);
+    }
+    
+    sect_per_track = heads * sectors;
+    tracks = (fs -> tot_sectors + sect_per_track - 1) / sect_per_track;
+    
+    BootP = __le16_to_cpu (boot -> BootP);
+    Infp0 = __le16_to_cpu (boot -> Infp0);
+    InfpX = __le16_to_cpu (boot -> InfpX);
+    InfTm = __le16_to_cpu (boot -> InfTm);
+    
+    if (boot -> dos4 == EXTENDED_BOOT &&
+        strncmp( boot->banner,"2M", 2 ) == 0 &&
+        BootP < SZ_STD_SECTOR &&
+        Infp0 < SZ_STD_SECTOR &&
+        InfpX < SZ_STD_SECTOR &&
+        InfTm < SZ_STD_SECTOR &&
+        BootP >= InfTm + 2 &&
+        InfTm >= InfpX &&
+        InfpX >= Infp0 && 
+        Infp0 >= 76 ) {
+
+        return (-1);
+    }
+
+    if (heads != NB_HEADS ||
+        tracks != NB_TRACKS ||
+        sectors != NB_SECTORS ||
+        __le16_to_cpu (boot -> secsiz) != SZ_STD_SECTOR ||
+        fs -> tot_sectors == 0 ||
+        (fs -> tot_sectors % sectors) != 0) {
+        return (-1);
+    }
+    
+    return (0);
+}
+
+
+#endif
diff --git a/fs/fdos/dos.h b/fs/fdos/dos.h
new file mode 100644
index 0000000..71701c9
--- /dev/null
+++ b/fs/fdos/dos.h
@@ -0,0 +1,177 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _DOS_H_
+#define _DOS_H_
+
+/* Definitions for Dos diskettes                                             */
+
+/* General definitions                                                       */
+#define SZ_STD_SECTOR   512             /* Standard sector size              */
+#define MDIR_SIZE	32		/* Direntry size                     */
+#define FAT_BITS        12              /* Diskette use 12 bits fat          */
+
+#define MAX_PATH	128		/* Max size of the MSDOS PATH        */
+#define MAX_DIR_SECS	64		/* Taille max d'un repertoire (en    */
+                                        /* secteurs)                         */
+/* Misc. definitions                                                         */
+#define DELMARK         '\xe5'
+#define EXTENDED_BOOT   (0x29)
+#define MEDIA_STD       (0xf0)
+#define JUMP_0_1        (0xe9)
+#define JUMP_0_2        (0xeb)
+
+/* Boot size is 256 bytes, but we need to read almost a sector, then
+   assume bootsize is 512                                                    */
+#define BOOTSIZE        512
+
+/* Fat definitions for 12 bits fat                                           */
+#define FAT12_MAX_NB    4086
+#define FAT12_LAST      0x0ff6
+#define FAT12_END       0x0fff
+
+/* file attributes                                                           */
+#define ATTR_READONLY           0x01
+#define ATTR_HIDDEN             0x02
+#define ATTR_SYSTEM             0x04
+#define ATTR_VOLUME             0x08
+#define ATTR_DIRECTORY          0x10
+#define ATTR_ARCHIVE            0x20
+#define ATTR_VSE                0x0f
+
+/* Name format                                                               */
+#define EXTCASE                 0x10
+#define BASECASE                0x8
+
+/* Definition of the boot sector                                             */
+#define BANNER_LG               8
+#define LABEL_LG                11
+
+typedef struct bootsector
+{
+    unsigned char jump [3];	/* 0  Jump to boot code                      */
+    char banner [BANNER_LG];	/* 3  OEM name & version                     */
+    unsigned short secsiz;	/* 11 Bytes per sector hopefully 512         */
+    unsigned char clsiz;	/* 13 Cluster size in sectors                */
+    unsigned short nrsvsect;	/* 14 Number of reserved (boot) sectors      */
+    unsigned char nfat;		/* 16 Number of FAT tables hopefully 2       */
+    unsigned short dirents;	/* 17 Number of directory slots              */
+    unsigned short psect;	/* 19 Total sectors on disk                  */
+    unsigned char descr;	/* 21 Media descriptor=first byte of FAT     */
+    unsigned short fatlen;	/* 22 Sectors in FAT                         */
+    unsigned short nsect;	/* 24 Sectors/track                          */
+    unsigned short nheads;	/* 26 Heads                                  */
+    unsigned int nhs;	        /* 28 number of hidden sectors               */
+    unsigned int bigsect;	/* 32 big total sectors                      */
+    unsigned char physdrive;	/* 36 physical drive ?                       */
+    unsigned char reserved;	/* 37 reserved                               */
+    unsigned char dos4;		/* 38 dos > 4.0 diskette                     */
+    unsigned int serial;        /* 39 serial number                          */
+    char label [LABEL_LG];	/* 43 disk label                             */
+    char fat_type [8];		/* 54 FAT type                               */
+    unsigned char res_2m;	/* 62 reserved by 2M                         */
+    unsigned char CheckSum;	/* 63 2M checksum (not used)                 */
+    unsigned char fmt_2mf;	/* 64 2MF format version                     */
+    unsigned char wt;		/* 65 1 if write track after format          */
+    unsigned char rate_0;	/* 66 data transfer rate on track 0          */
+    unsigned char rate_any;	/* 67 data transfer rate on track<>0         */
+    unsigned short BootP;	/* 68 offset to boot program                 */
+    unsigned short Infp0;	/* 70 T1: information for track 0            */
+    unsigned short InfpX;	/* 72 T2: information for track<>0           */
+    unsigned short InfTm;	/* 74 T3: track sectors size table           */
+    unsigned short DateF;	/* 76 Format date                            */
+    unsigned short TimeF;	/* 78 Format time                            */
+    unsigned char junk [BOOTSIZE - 80];	/* 80 remaining data                 */
+} __attribute__ ((packed)) BootSector_t;
+
+/* Structure d'une entree de repertoire                                      */
+typedef struct directory {
+    char name [8];		/* file name                                 */
+    char ext [3];		/* file extension                            */
+    unsigned char attr;		/* attribute byte                            */
+    unsigned char Case;		/* case of short filename                    */
+    unsigned char reserved [9];	/* ??                                        */
+    unsigned char time [2];	/* time stamp                                */
+    unsigned char date [2];	/* date stamp                                */
+    unsigned short start;	/* starting cluster number                   */
+    unsigned int size;	        /* size of the file                          */
+} __attribute__ ((packed))  Directory_t;
+
+
+
+#define MAX_VFAT_SUBENTRIES 20
+#define VSE_NAMELEN 13
+
+#define VSE1SIZE 5
+#define VSE2SIZE 6
+#define VSE3SIZE 2
+
+#define VBUFSIZE ((MAX_VFAT_SUBENTRIES * VSE_NAMELEN) + 1)
+
+#define MAX_VNAMELEN (255)
+
+#define VSE_PRESENT 0x01
+#define VSE_LAST 0x40
+#define VSE_MASK 0x1f
+
+/* Flag used by vfat_lookup                                                  */
+#define DO_OPEN         1
+#define ACCEPT_PLAIN    0x20
+#define ACCEPT_DIR      0x10
+#define ACCEPT_LABEL    0x08
+#define SINGLE          2
+#define MATCH_ANY       0x40
+
+struct vfat_subentry {
+    unsigned char id;		        /* VSE_LAST pour la fin, VSE_MASK    */
+                                        /* pour un VSE                       */
+    char text1 [VSE1SIZE * 2];          /* Caracteres encodes sur 16 bits    */
+    unsigned char attribute;	        /* 0x0f pour les VFAT                */
+    unsigned char hash1;		/* toujours 0                        */
+    unsigned char sum;		        /* Checksum du nom court             */
+    char text2 [VSE2SIZE * 2];          /* Caracteres encodes sur 16 bits    */
+    unsigned char sector_l;             /* 0 pour les VFAT                   */
+    unsigned char sector_u;		/* 0 pour les VFAT                   */
+    char text3 [VSE3SIZE * 2];          /* Caracteres encodes sur 16 bits    */
+} __attribute__ ((packed)) ;
+
+struct vfat_state {
+    char name [VBUFSIZE];
+    int status;             /* is now a bit map of 32 bits                   */
+    int subentries;
+    unsigned char sum;      /* no need to remember the sum for each          */
+                            /*   entry, it is the same anyways               */
+} __attribute__ ((packed)) ;
+
+/* Conversion macros                                                         */
+#define	DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
+#define	DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
+#define	DOS_DAY(dir) ((dir)->date[0] & 0x1f)
+#define	DOS_HOUR(dir) ((dir)->time[1] >> 3)
+#define	DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
+#define	DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
+
+
+#endif
+
diff --git a/fs/fdos/fat.c b/fs/fdos/fat.c
new file mode 100644
index 0000000..42df755
--- /dev/null
+++ b/fs/fdos/fat.c
@@ -0,0 +1,145 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+
+/*-----------------------------------------------------------------------------
+ * fat_decode -- 
+ *-----------------------------------------------------------------------------
+ */
+unsigned int fat_decode (Fs_t *fs, unsigned int num)
+{
+    unsigned int start = num * 3 / 2;
+    unsigned char *address = fs -> fat_buf + start;
+    
+    if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR))
+        return 1;
+    
+    if (num & 1)
+        return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4);
+    else
+        return ((address [1] & 0xf) << 8) | (address [0] & 0xff );
+}
+/*-----------------------------------------------------------------------------
+ * check_fat -- 
+ *-----------------------------------------------------------------------------
+ */
+static int check_fat (Fs_t *fs)
+{
+    int i, f;
+
+    /* Cluster verification                                                  */
+    for (i = 3 ; i < fs -> num_clus; i++){
+        f = fat_decode (fs, i);
+        if (f < FAT12_LAST && f > fs -> num_clus){
+            /* Wrong cluster number detected                                 */
+            return (-1);
+        }
+    }
+    return (0);
+}
+/*-----------------------------------------------------------------------------
+ * read_one_fat -- 
+ *-----------------------------------------------------------------------------
+ */
+static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat)
+{
+    if (dev_read (fs -> fat_buf,
+                  (fs -> fat_start + nfat * fs -> fat_len),
+                  fs -> fat_len) < 0) {
+        return (-1);
+    }
+
+    if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) {
+        if ((fs -> fat_buf [0] != boot -> descr &&
+             (fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) ||
+            fs -> fat_buf [0] < MEDIA_STD){
+            /* Unknown Media                                                 */
+            return (-1);
+        }
+        if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){
+            /* FAT doesn't start with good values                            */
+            return (-1);
+        }
+    }
+
+    if (fs -> num_clus >= FAT12_MAX_NB) {
+        /* Too much clusters                                                 */
+        return (-1);
+    }
+
+    return check_fat (fs);
+}
+/*-----------------------------------------------------------------------------
+ * read_fat -- 
+ *-----------------------------------------------------------------------------
+ */
+int read_fat (BootSector_t *boot, Fs_t *fs)
+{
+    unsigned int buflen;
+    int i;
+
+    /* Allocate Fat Buffer                                                   */
+    buflen = fs -> fat_len * SZ_STD_SECTOR;
+    if (fs -> fat_buf) {
+        free (fs -> fat_buf);
+    }
+
+    if ((fs -> fat_buf = malloc (buflen)) == NULL) {
+        return (-1);
+    }
+
+    /* Try to read each Fat                                                  */
+    for (i = 0; i< fs -> nb_fat; i++){
+        if (read_one_fat (boot, fs, i) == 0) {
+            /* Fat is OK                                                     */
+            fs -> num_fat = i;
+            break;
+        }
+    }
+
+    if (i == fs -> nb_fat){
+        return (-1);
+    }
+    
+    if (fs -> fat_len > (((fs -> num_clus + 2) *
+                          (FAT_BITS / 4) -1 ) / 2 /
+                         SZ_STD_SECTOR + 1)) {
+        return (-1);
+    }
+    return (0);
+}
+
+
+ 
+
+#endif
diff --git a/fs/fdos/fdos.c b/fs/fdos/fdos.c
new file mode 100644
index 0000000..8963f42
--- /dev/null
+++ b/fs/fdos/fdos.c
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+#include <malloc.h>
+#include "dos.h"
+#include "fdos.h"
+
+
+const char *month [] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+Fs_t    fs;
+File_t  file;
+
+/*-----------------------------------------------------------------------------
+ * dos_open -- 
+ *-----------------------------------------------------------------------------
+ */
+int dos_open(char *name)
+{
+    int lg;
+    int entry;
+    char *fname;
+    
+    /* We need to suppress the " char around the name                        */
+    if (name [0] == '"') {
+        name ++;
+    }
+    lg = strlen (name);
+    if (name [lg - 1] == '"') {
+        name [lg - 1] = '\0';
+    }
+
+    /* Open file system                                                      */
+    if (fs_init (&fs) < 0) {
+        return -1;
+    }
+
+    /* Init the file descriptor                                              */
+    file.name = name;
+    file.fs = &fs;
+    
+    /* find the subdirectory containing the file                             */
+    if (open_subdir (&file) < 0) {
+        return (-1);
+    }
+
+    fname = basename (name);
+
+    /* if we try to open root directory                                      */
+    if (*fname == '\0') {
+        file.file = file.subdir;
+        return (0);
+    }
+    
+    /* find the file in the subdir                                           */
+    entry = 0;
+    if (vfat_lookup (&file.subdir,
+                     file.fs,
+                     &file.file.dir,
+                     &entry,
+                     0,
+                     fname,
+                     ACCEPT_DIR | ACCEPT_PLAIN | SINGLE | DO_OPEN,
+                     0,
+                     &file.file) != 0) {
+        /* File not found                                                    */
+        printf ("File not found\n");
+        return (-1);
+    }
+
+    return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * dos_read -- 
+ *-----------------------------------------------------------------------------
+ */
+int dos_read (ulong addr)
+{
+    int read = 0, nb;
+
+    /* Try to boot a directory ?                                             */
+    if (file.file.dir.attr & (ATTR_DIRECTORY | ATTR_VOLUME)) {
+        printf ("Unable to boot %s !!\n", file.name);
+        return (-1);
+    }
+    while (read < file.file.FileSize) {
+        PRINTF ("read_file (%ld)\n", (file.file.FileSize - read));
+        nb = read_file (&fs,
+                        &file.file,
+                        (char *)addr + read,
+                        read,
+                        (file.file.FileSize - read));
+        PRINTF ("read_file -> %d\n", nb);
+        if (nb < 0) {
+            printf ("read error\n");
+            return (-1);
+        }
+        read += nb;
+    }
+    return (read);
+}
+/*-----------------------------------------------------------------------------
+ * dos_dir -- 
+ *-----------------------------------------------------------------------------
+ */
+int dos_dir (void)
+{
+    int entry;
+    Directory_t dir;
+    char *name;
+    
+    
+    if ((file.file.dir.attr & ATTR_DIRECTORY) == 0) {
+        printf ("%s: not a directory !!\n", file.name);
+        return (1);
+    }
+    entry = 0;
+    if ((name = malloc (MAX_VNAMELEN + 1)) == NULL) {
+        PRINTF ("Allcation error\n");
+        return (1);
+    }
+    
+    while (vfat_lookup (&file.file,
+                        file.fs,
+                        &dir,
+                        &entry,
+                        0,
+                        NULL,
+                        ACCEPT_DIR | ACCEPT_PLAIN | MATCH_ANY,
+                        name,
+                        NULL) == 0) {
+        /* Display file info                                                 */
+        printf ("%3.3s %9d %s %02d %04d %02d:%02d:%02d %s\n",
+                (dir.attr & ATTR_DIRECTORY) ? "dir" : "   ",
+                __le32_to_cpu (dir.size),
+                month [DOS_MONTH (&dir) - 1],
+                DOS_DAY (&dir),
+                DOS_YEAR (&dir),
+                DOS_HOUR (&dir),
+                DOS_MINUTE (&dir),
+                DOS_SEC (&dir),
+                name);
+        
+    }
+    free (name);
+    return (0);
+}
+
+#endif
diff --git a/fs/fdos/fdos.h b/fs/fdos/fdos.h
new file mode 100644
index 0000000..18076d8
--- /dev/null
+++ b/fs/fdos/fdos.h
@@ -0,0 +1,117 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FDOS_H_
+#define _FDOS_H_
+
+
+#undef	FDOS_DEBUG
+
+#ifdef	FDOS_DEBUG
+#define	PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Data structure describing media                                           */
+typedef struct fs
+{
+    unsigned long       tot_sectors;
+
+    int                 cluster_size;
+    int                 num_clus;
+    
+    int                 fat_start;
+    int                 fat_len;
+    int                 nb_fat;
+    int                 num_fat;
+    
+    int                 dir_start;
+    int                 dir_len;
+
+    unsigned char       *fat_buf;
+    
+} Fs_t;
+
+/* Data structure describing one file system slot                            */
+typedef struct slot {
+    int (*map) (struct fs *fs,
+                struct slot *file,
+                int where,
+                int *len);
+    unsigned long FileSize;
+
+    unsigned short int FirstAbsCluNr;
+    unsigned short int PreviousAbsCluNr;
+    unsigned short int PreviousRelCluNr;
+
+    Directory_t dir;
+} Slot_t;
+
+typedef struct file {
+    char                *name;
+    int                 Case;
+    Fs_t                *fs;
+    Slot_t              subdir;
+    Slot_t              file;
+} File_t;
+
+
+/* dev.c                                                                     */
+int dev_read (void *buffer, int where, int len);
+int dev_open (void);
+int check_dev (BootSector_t *boot, Fs_t *fs);
+
+/* fat.c                                                                     */
+unsigned int fat_decode (Fs_t *fs, unsigned int num);
+int read_fat (BootSector_t *boot, Fs_t *fs);
+
+/* vfat.c                                                                    */
+int vfat_lookup (Slot_t *dir,
+                 Fs_t *fs,
+                 Directory_t *dirent,
+                 int *entry,
+                 int *vfat_start,
+                 char *filename, 
+                 int flags,
+                 char *outname,
+                 Slot_t *file);
+
+/* subdir.c                                                                  */
+char *basename (char *name);
+int open_subdir (File_t *desc);
+int open_file (Slot_t *file, Directory_t *dir);
+int read_file (Fs_t *fs,
+               Slot_t *file,
+               char *buf,
+               int where,
+               int len);
+void init_subdir (void);
+
+/* fs.c                                                                      */
+int fs_init (Fs_t *fs);
+
+
+#endif
+
diff --git a/fs/fdos/fs.c b/fs/fdos/fs.c
new file mode 100644
index 0000000..68bbde0
--- /dev/null
+++ b/fs/fdos/fs.c
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+
+/*-----------------------------------------------------------------------------
+ * fill_fs -- Read info on file system 
+ *-----------------------------------------------------------------------------
+ */
+static int fill_fs (BootSector_t *boot, Fs_t *fs)
+{
+    
+    fs -> fat_start = __le16_to_cpu (boot -> nrsvsect);
+    fs -> fat_len = __le16_to_cpu (boot -> fatlen);
+    fs -> nb_fat = boot -> nfat;
+    
+    fs -> dir_start = fs -> fat_start + fs -> nb_fat * fs -> fat_len;
+    fs -> dir_len = __le16_to_cpu (boot -> dirents) * MDIR_SIZE / SZ_STD_SECTOR;
+    fs -> cluster_size = boot -> clsiz;
+    fs -> num_clus = (fs -> tot_sectors - fs -> dir_start - fs -> dir_len) / fs -> cluster_size;
+
+    return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * fs_init -- 
+ *-----------------------------------------------------------------------------
+ */
+int fs_init (Fs_t *fs)
+{
+    BootSector_t *boot;
+
+    /* Initialize physical device                                            */
+    if (dev_open () < 0) {
+        PRINTF ("Unable to initialize the fdc\n");
+        return (-1);
+    }
+    init_subdir ();
+    
+    /* Allocate space for read the boot sector                               */
+    if ((boot = (BootSector_t *)malloc (sizeof (BootSector_t))) == NULL) {
+        PRINTF ("Unable to allocate space for boot sector\n");
+        return (-1);
+    }
+    
+    /* read boot sector                                                      */
+    if (dev_read (boot, 0, 1)){
+        PRINTF ("Error during boot sector read\n");
+        free (boot);
+        return (-1);
+    }
+
+    /* we verify it'a a DOS diskette                                         */
+    if (boot -> jump [0] !=  JUMP_0_1 && boot -> jump [0] !=  JUMP_0_2) {
+        PRINTF ("Not a DOS diskette\n");
+        free (boot);
+        return (-1);
+    }
+
+    if (boot -> descr < MEDIA_STD) {
+        /* We handle only recent medias (type F0)                            */
+        PRINTF ("unrecognized diskette type\n");
+        free (boot);
+        return (-1);
+    }
+
+    if (check_dev (boot, fs) < 0) {
+        PRINTF ("Bad diskette\n");
+        free (boot);
+        return (-1);
+    }
+    
+    if (fill_fs (boot, fs) < 0) {
+        free (boot);
+
+        return (-1);
+    }
+
+    /* Read FAT                                                              */
+    if (read_fat (boot, fs) < 0) {
+        free (boot);
+        return (-1);
+    }
+
+    free (boot);
+    return (0);
+}
+
+
+
+#endif
diff --git a/fs/fdos/subdir.c b/fs/fdos/subdir.c
new file mode 100644
index 0000000..5911f2e
--- /dev/null
+++ b/fs/fdos/subdir.c
@@ -0,0 +1,348 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+static int cache_sect;
+static unsigned char cache [SZ_STD_SECTOR];
+
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+static int descend (Slot_t *parent,
+             Fs_t *fs,
+                    char *path);
+
+/*-----------------------------------------------------------------------------
+ * init_subdir -- 
+ *-----------------------------------------------------------------------------
+ */
+void init_subdir (void)
+{
+    cache_sect = -1;
+}
+/*-----------------------------------------------------------------------------
+ * basename -- 
+ *-----------------------------------------------------------------------------
+ */
+char *basename (char *name)
+{
+    register char *cptr;
+
+    if (!name || !*name) {
+        return ("");
+    }
+    
+    for (cptr= name; *cptr++; );
+    while (--cptr >= name) {
+	if (*cptr == '/')    {
+            return (cptr + 1);
+	}
+    }
+    return(name);
+}
+/*-----------------------------------------------------------------------------
+ * root_map -- 
+ *-----------------------------------------------------------------------------
+ */
+static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
+{
+    *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
+    if (*len < 0 ) {
+        *len = 0;
+        return (-1);
+    }
+    return fs -> dir_start * SZ_STD_SECTOR + where;
+}
+/*-----------------------------------------------------------------------------
+ * normal_map -- 
+ *-----------------------------------------------------------------------------
+ */
+static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
+{
+    int offset;
+    int NrClu;
+    unsigned short RelCluNr;
+    unsigned short CurCluNr;
+    unsigned short NewCluNr;
+    unsigned short AbsCluNr;
+    int clus_size;
+
+    clus_size = fs -> cluster_size * SZ_STD_SECTOR;
+    offset = where % clus_size;
+
+    *len = min (*len, file -> FileSize - where);
+
+    if (*len < 0 ) {
+        *len = 0;
+        return (0);
+    }
+
+    if (file -> FirstAbsCluNr < 2){
+        *len = 0;
+        return (0);
+    }
+
+    RelCluNr = where / clus_size;
+	
+    if (RelCluNr >= file -> PreviousRelCluNr){
+        CurCluNr = file -> PreviousRelCluNr;
+        AbsCluNr = file -> PreviousAbsCluNr;
+    } else {
+        CurCluNr = 0;
+        AbsCluNr = file -> FirstAbsCluNr;
+    }
+
+
+    NrClu = (offset + *len - 1) / clus_size;
+    while (CurCluNr <= RelCluNr + NrClu) {
+        if (CurCluNr == RelCluNr){
+            /* we have reached the beginning of our zone. Save
+             * coordinates */
+            file -> PreviousRelCluNr = RelCluNr;
+            file -> PreviousAbsCluNr = AbsCluNr;
+        }
+        NewCluNr = fat_decode (fs, AbsCluNr);
+        if (NewCluNr == 1 || NewCluNr == 0) {
+            PRINTF("Fat problem while decoding %d %x\n", 
+                    AbsCluNr, NewCluNr);
+            return (-1);
+        }
+        if (CurCluNr == RelCluNr + NrClu) {
+            break;
+        }
+
+        if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
+            *len = 0;
+            return 0;
+        }
+
+        if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
+            break;
+        CurCluNr++;
+        AbsCluNr = NewCluNr;
+    }
+
+    *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
+
+    return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
+             fs -> dir_start + fs -> dir_len) *
+            SZ_STD_SECTOR + offset);
+}
+/*-----------------------------------------------------------------------------
+ * open_subdir -- open the subdir containing the file
+ *-----------------------------------------------------------------------------
+ */
+int open_subdir (File_t *desc)
+{
+    char *pathname;
+    char *tmp, *s, *path;
+    char terminator;
+    
+    if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
+        return (-1);
+    }
+    
+    strcpy (pathname, desc -> name);
+    
+    /* Suppress file name                                                    */
+    tmp = basename (pathname);
+    *tmp = '\0';
+
+    /* root directory  init                                                  */
+    desc -> subdir.FirstAbsCluNr = 0;
+    desc -> subdir.FileSize = -1;
+    desc -> subdir.map = root_map;
+    desc -> subdir.dir.attr = ATTR_DIRECTORY;
+    
+    tmp = pathname;
+    for (s = tmp; ; ++s) {
+        if (*s == '/' || *s == '\0') {
+            path = tmp;
+            terminator = *s;
+            *s = '\0';
+            if (s != tmp && strcmp (path,".")) {
+                if (descend (&desc -> subdir, desc -> fs, path) < 0) {
+                    free (pathname);
+                    return (-1);
+                }
+            }
+            if (terminator == 0) {
+                break;
+            }
+            tmp = s + 1;
+        }
+    }
+    free (pathname);
+    return (0);
+}
+/*-----------------------------------------------------------------------------
+ * descend -- 
+ *-----------------------------------------------------------------------------
+ */
+static int descend (Slot_t *parent,
+             Fs_t *fs,
+             char *path)
+{
+    int entry;
+    Slot_t SubDir;
+
+    if(path[0] == '\0' || strcmp (path, ".") == 0) {
+        return (0);
+    }
+    
+
+    entry = 0;
+    if (vfat_lookup (parent,
+                     fs,
+                     &(SubDir.dir),
+                     &entry,
+                     0,
+                     path,
+                     ACCEPT_DIR | SINGLE | DO_OPEN,
+                     0,
+                     &SubDir) == 0) {
+        *parent = SubDir;
+        return (0);
+    }
+
+    if (strcmp(path, "..") == 0) {
+        parent -> FileSize = -1;
+        parent -> FirstAbsCluNr = 0;
+        parent -> map = root_map;
+        return (0);
+    }
+    return (-1);
+}
+/*-----------------------------------------------------------------------------
+ * open_file -- 
+ *-----------------------------------------------------------------------------
+ */
+int open_file (Slot_t *file, Directory_t *dir)
+{
+    int first;
+    unsigned long size;
+
+    first = __le16_to_cpu (dir -> start);
+
+    if(first == 0 &&
+       (dir -> attr & ATTR_DIRECTORY) != 0) {
+        file -> FirstAbsCluNr = 0;
+        file -> FileSize = -1;
+        file -> map = root_map;
+        return (0);
+    }
+	
+    if ((dir -> attr & ATTR_DIRECTORY) != 0) {
+        size = (1UL << 31) - 1;
+    }
+    else {
+        size = __le32_to_cpu (dir -> size);
+    }
+
+    file -> map = normal_map;
+    file -> FirstAbsCluNr = first;
+    file -> PreviousRelCluNr = 0xffff;
+    file -> FileSize = size;
+    return (0);
+}
+/*-----------------------------------------------------------------------------
+ * read_file -- 
+ *-----------------------------------------------------------------------------
+ */
+int read_file (Fs_t *fs,
+               Slot_t *file,
+               char *buf,
+               int where,
+               int len)
+{
+    int pos;
+    int read, nb, sect, offset;
+    
+    pos = file -> map (fs, file, where, &len);
+    if  (pos < 0) {
+        return -1;
+    }
+    if (len == 0) {
+        return (0);
+    }
+
+    /* Compute sector number                                                 */
+    sect = pos / SZ_STD_SECTOR;
+    offset = pos % SZ_STD_SECTOR;
+    read = 0;
+    
+    if (offset) {
+        /* Read doesn't start at the sector beginning. We need to use our    */
+        /* cache                                                             */
+        if (sect != cache_sect) {
+            if (dev_read (cache, sect, 1) < 0) {
+                return (-1);
+            }
+            cache_sect = sect;
+        }
+        nb = min (len, SZ_STD_SECTOR - offset);
+        
+        memcpy (buf, cache + offset, nb);
+        read += nb;
+        len -= nb;
+        sect += 1;
+    }
+
+    if (len > SZ_STD_SECTOR) {
+        nb = (len - 1) / SZ_STD_SECTOR;
+        if (dev_read (buf + read, sect, nb) < 0) {
+            return ((read) ? read : -1);
+        }
+        /* update sector position                                            */
+        sect += nb;
+
+        /* Update byte position                                              */
+        nb *= SZ_STD_SECTOR;
+        read += nb;
+        len -= nb;
+    }
+
+    if (len) {
+        if (sect != cache_sect) {
+            if (dev_read (cache, sect, 1) < 0) {
+                return ((read) ? read : -1);
+                cache_sect = -1;
+            }
+            cache_sect = sect;
+        }
+        
+        memcpy (buf + read, cache, len);
+        read += len;
+    }
+    return (read);
+}
+#endif
diff --git a/fs/fdos/vfat.c b/fs/fdos/vfat.c
new file mode 100644
index 0000000..f828795
--- /dev/null
+++ b/fs/fdos/vfat.c
@@ -0,0 +1,357 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT  p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+#include <linux/ctype.h>
+
+#include "dos.h"
+#include "fdos.h"
+
+static int dir_read (Fs_t *fs,
+                     Slot_t *dir,
+                     Directory_t *dirent,
+                     int num,
+                     struct vfat_state *v);
+
+static int unicode_read (char *in, char *out, int num);
+static int match (const char *s, const char *p);
+static unsigned char sum_shortname (char *name);
+static int check_vfat (struct vfat_state *v, Directory_t *dir);
+static char *conv_name (char *name, char *ext, char Case, char *ans);
+
+
+/*-----------------------------------------------------------------------------
+ * clear_vfat -- 
+ *-----------------------------------------------------------------------------
+ */
+static void clear_vfat (struct vfat_state *v)
+{
+    v -> subentries = 0;
+    v -> status = 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * vfat_lookup -- 
+ *-----------------------------------------------------------------------------
+ */
+int vfat_lookup (Slot_t *dir,
+                 Fs_t *fs,
+                 Directory_t *dirent,
+                 int *entry,
+                 int *vfat_start,
+                 char *filename, 
+                 int flags,
+                 char *outname,
+                 Slot_t *file)
+{
+    int found;
+    struct vfat_state vfat;
+    char newfile [VSE_NAMELEN];
+    int vfat_present = 0;
+
+    if (*entry == -1) {
+        return -1;
+    }
+
+    found = 0;
+    clear_vfat (&vfat);
+    while (1) {
+        if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
+            if (vfat_start) {
+                *vfat_start = *entry;
+            }
+            break;
+        }
+        (*entry)++;
+
+        /* Empty slot                                                        */
+        if (dirent -> name[0] == '\0'){
+            if (vfat_start == 0) {
+                break;
+            }
+            continue;
+        }
+
+        if (dirent -> attr == ATTR_VSE) {
+            /* VSE entry, continue                                           */
+            continue;
+        }
+        if ( (dirent -> name [0] == DELMARK) ||
+             ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
+              (flags & ACCEPT_DIR) == 0) ||
+             ((dirent -> attr & ATTR_VOLUME) != 0 &&
+              (flags & ACCEPT_LABEL) == 0) ||
+             (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
+              (flags & ACCEPT_PLAIN) == 0)) {
+            clear_vfat (&vfat);
+            continue;
+        }
+
+        vfat_present = check_vfat (&vfat, dirent);
+        if (vfat_start) {
+            *vfat_start = *entry - 1;
+            if (vfat_present) {
+                *vfat_start -= vfat.subentries;
+            }
+        }
+
+        if (dirent -> attr & ATTR_VOLUME) {
+            strncpy (newfile, dirent -> name, 8);
+            newfile [8] = '\0';
+            strncat (newfile, dirent -> ext, 3);
+            newfile [11] = '\0';
+        }
+        else {
+            conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
+        }
+
+        if (flags & MATCH_ANY) {
+            found = 1;
+            break;
+        }
+
+        if ((vfat_present && match (vfat.name, filename)) ||
+            (match (newfile, filename))) {
+            found = 1;
+            break;
+        }
+        clear_vfat (&vfat);
+    }
+
+    if (found) {
+        if ((flags & DO_OPEN) && file) {
+            if (open_file (file, dirent) < 0) {
+                return (-1);
+            }
+        }
+        if (outname) {
+            if (vfat_present) {
+                strcpy (outname, vfat.name);
+            }
+            else {
+                strcpy (outname, newfile);
+            }
+        }
+        return (0);                    /* File found                         */
+    } else {
+        *entry = -1;
+        return -1;                      /* File not found                    */
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * dir_read -- Read one directory entry
+ *-----------------------------------------------------------------------------
+ */
+static int dir_read (Fs_t *fs,
+              Slot_t *dir,
+              Directory_t *dirent,
+              int num,
+              struct vfat_state *v)
+{
+
+    /* read the directory entry                                              */
+    if (read_file (fs,
+                   dir,
+                   (char *)dirent,
+                   num * MDIR_SIZE,
+                   MDIR_SIZE) != MDIR_SIZE) {
+        return (-1);
+    }
+
+    if (v && (dirent -> attr == ATTR_VSE)) {
+        struct vfat_subentry *vse;
+        unsigned char id, last_flag;
+        char *c;
+
+        vse = (struct vfat_subentry *) dirent;
+        id = vse -> id & VSE_MASK;
+        last_flag = (vse -> id & VSE_LAST);
+        if (id > MAX_VFAT_SUBENTRIES) {
+            /* Invalid VSE entry                                             */
+            return (-1);
+        }
+
+
+        /* Decode VSE                                                        */
+        if(v -> sum != vse -> sum) {
+            clear_vfat (v);
+            v -> sum = vse -> sum;
+        }
+
+        
+        v -> status |= 1 << (id - 1);
+        if (last_flag) {
+            v -> subentries = id;
+        }
+
+        c = &(v -> name [VSE_NAMELEN * (id - 1)]);
+        c += unicode_read (vse->text1, c, VSE1SIZE);
+        c += unicode_read (vse->text2, c, VSE2SIZE);
+        c += unicode_read (vse->text3, c, VSE3SIZE);
+		
+        if (last_flag) {
+            *c = '\0';	        /* Null terminate long name                  */
+        }
+        
+    }
+    return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * unicode_read -- 
+ *-----------------------------------------------------------------------------
+ */
+static int unicode_read (char *in, char *out, int num)
+{
+    int j;
+    
+    for (j = 0; j < num; ++j) {
+        if (in [1])
+            *out = '_';
+        else
+            *out = in [0];
+        out ++;
+        in += 2;
+    }
+    return num;
+}
+
+/*-----------------------------------------------------------------------------
+ * match -- 
+ *-----------------------------------------------------------------------------
+ */
+static int match (const char *s, const char *p)
+{
+
+    for (; *p != '\0'; ) {
+        if (toupper (*s) != toupper (*p)) {
+            return (0);
+        }
+        p++;
+        s++;
+    }
+    
+    if (*s != '\0') {
+        return (0);
+    }
+    else {
+        return (1);
+    }
+}
+/*-----------------------------------------------------------------------------
+ * sum_shortname -- 
+ *-----------------------------------------------------------------------------
+ */
+static unsigned char sum_shortname (char *name)
+{
+    unsigned char sum;
+    int j;
+    
+    for (j = sum = 0; j < 11; ++j) {
+        sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
+            (name [j] ? name [j] : ' ');
+    }
+    return (sum);
+}
+/*-----------------------------------------------------------------------------
+ * check_vfat -- 
+ * Return 1 if long name is valid, 0 else
+ *-----------------------------------------------------------------------------
+ */
+static int check_vfat (struct vfat_state *v, Directory_t *dir)
+{
+    char name[12];
+    
+    if (v -> subentries == 0) {
+        return 0;
+    }
+    
+    strncpy (name, dir -> name, 8);
+    strncpy (name + 8, dir -> ext, 3);
+    name [11] = '\0';
+    
+    if (v -> sum != sum_shortname (name)) {
+        return 0;
+    }
+    
+    if( (v -> status & ((1 << v -> subentries) - 1)) !=
+        (1 << v -> subentries) - 1) {
+        return 0;
+    }
+    v->name [VSE_NAMELEN * v -> subentries] = 0;
+    
+    return 1;
+}
+/*-----------------------------------------------------------------------------
+ * conv_name -- 
+ *-----------------------------------------------------------------------------
+ */
+static char *conv_name (char *name, char *ext, char Case, char *ans)
+{
+    char tname [9], text [4];
+    int i;
+
+    i = 0;
+    while (i < 8 && name [i] != ' ' && name [i] != '\0') {
+        tname [i] = name [i];
+        i++;
+    }
+    tname [i] = '\0';
+    
+    if (Case & BASECASE) {
+        for (i = 0; i < 8 && tname [i]; i++) {
+            tname [i] = tolower (tname [i]);
+        }
+    }
+
+    i = 0;
+    while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
+        text [i] = ext [i];
+        i++;
+    }
+    text [i] = '\0';
+
+    if (Case & EXTCASE){
+        for (i = 0; i < 3 && text [i]; i++) {
+            text [i] = tolower (text [i]);
+        }
+    }
+
+    if (*text) {
+        strcpy (ans, tname);
+        strcat (ans, ".");
+        strcat (ans, text);
+    }
+    else {
+        strcpy(ans, tname);
+    }
+    return (ans);
+}
+
+
+#endif