"eefs" EEPROM File System ------------------------- Version 0.20 Date 2011-09-19 • 8-bit devices • 16-bit devices • I²C driver eeproms This file describes device drivers for devices on the K1 hobbyist-grade peripheral bus. These are stored in I²C EEproms on the K1-bus card. These EEproms contain a file system, which is the 8-bit variant of the following described 8-bit or 16-bit file system. 8-Bit vs. 16-Bit Devices ------------------------ 8-bit file systems are used on 8-bit devices and 16-bit file systems are used on 16-bit devices. !! "Byte" refers to 8-bit bytes on 8-bit devices and file systems and to 16-bit wide bytes on 16-bit devices and file systems. !! "2 Bytes" refers to 2 bytes summing up to a 16-bit number on 8-bit devices or a 32-bit number on 16-bit devices. The high byte comes first. File names are stored with one byte per character, using Latin-1 (8-bit subset of unicode) on 8-bit devices and UCS-2 (16-bit subset of unicode) on 16-bit devices. An 8-bit file system can only reside on a device with at most 0xFFFF device blocks and can itself have at most 0xFFFF file system blocks. Files on a 8-bit file system can contain at most 0xFFFF bytes. Device Layout ------------- The data of a device with a "eefs" file system starts with magic bytes, information about the file system's block size, total block count and the root directory. The name of the root directory is used as the name for the file system. The "root block" extends to at least 32 bytes if the physical block size is smaller. addr data example description ------ ---------- ---------- ------------------------------------- 0x0000 byte[6] "eefsv1" magic bytes for file system detection 0x0006 byte 4 log(2) of file system block size 0x0007 2 bytes 2048 total file system block count 0x0009 DirEntry root directory unused up to max(32,fs_blocksize) Directory File -------------- A directory is a file which contains raw directory entries without gap or filler. The directory file of an empty directory has length 0 and occupies no space. Directory Entry --------------- A directory entry contains information about file type, file name, file size and the location of one (or potentially more) block ranges used for a file. Typically a file is stored in consecutive file system blocks. Then only one Block is needed to define it's location on disk, but it may be split into multiple block ranges. data example description ---------- ---------- ------------------------------------- byte 1 file type 2 bytes 666 file size [bytes] byte 6 file name length: max. 127 bytes! byte[] "foobar" file name byte 1 block list length Block[] block list File Type --------- 2 = Directory file 4 = Regular file Bit 0 indicates whether this is a wide file (with 16-bit bytes) or a small file (with 8-bit bytes). Directory files on a 8-bit device must be 8-bit, directory files on a 16-bit device must be 16-bit. bit 0 0 8-bit file 1 16-bit file Block Layout ------------ A Block defines position and length of a consecutive range of file system blocks. data example description ---------- ---------- ------------------------------------- 2 bytes 33 start block 2 bytes 42 block count Root Directory -------------- The root directory entry is not stored in a parent directory file because there is no parent directory for the root directory. Instead the root directory entry is stored in block 0 of the file system. If the block size of the file system is less than 32 bytes, then the first 32 bytes are used for magic bytes etc. and the root directory entry. (see Device Layout above.) This limits the number of Blocks for the root directory, which is only a theoretical limit, because a single Block can describe any number of consecutive file system blocks. The root directory's name is used as the name for the file system. Free Block List --------------- There is no free block list. Instead the root directory contains a sub directory ".trash" which contains any number of files and directories which are deleted. When new blocks are needed for growing a file then they are removed from the first file in this directory. When files are deleted they are appended to this directory. Whole directory trees may be moved into the ".trash" directory in one go. In the simplest case the ".trash" directory contains only one file which extends over all free blocks in the file system. Device Block Size vs. File System Block Size -------------------------------------------- The file system block size must be at least the same size as the device's physical block size, so that file system blocks can be easily read and written by calling the device's block read and write functions. Especially for small EEproms it is desirable to use very small block sizes, smaller than the physical EEprom block size of 64 bytes. This must be handled by the I²C EEprom device driver which should pretend to use smaller blocks, ideally block size = 1 byte for EEproms up to 32 kByte. The I²C EEprom device driver itself must be supplied by the boot system. Directory Layout for I²C Driver EEproms ======================================= dir "device_name" root directory | +----- dir ".trash" | | | +----- file(s) | +----- file "info" Basic informationen; see below | +----- dir "drvr" Universal bytecoded driver | | | +----- file "A" Definition of global variables | +----- file "D" Definition of structured data types | +----- file "INT" Bytecode for the interrupt service function | +----- file "setctl" Bytecode for the "setctl" function | +----- file "getctl" Bytecode for the "getctl" function | +----- file "init" Bytecode for the "init" function | +----- ... | +----- dir "bin" Universal bytecoded utilities | | | +----- file "foofile" Bytecoded executable | +----- ... | +----- ... Besides the required directories and files the EEprom may contain any additional data. If a system wishes to store an alternate, machine coded driver in the EEprom's file system, then it should create a directory with an appropriate, unique name identifying the system and therein directories "drvr" and "bin". File "info" ----------- This file contains general information about the device. This should be a Latin-1 (UCS-1) encoded text file with char(10) line delimiters. Suggested contents: "aaaabbccdd" Basic informationens (bit fields & values) -required- "FooCard 1.0a CC-BY" Card name etc. for display at boot time -required- "2008-12-24 18:30" version date "CF-Card Adapter" description "Kio " developer name or email "MyCompany" manufacturer name or URI "Copyright (c) MyCompany 2008" copyright message "License: http://www..." verbose license message "Help: /dev/hd/help" help message "Forum: http://..." help message Basic Informations Bit Fileds ----------------------------- All bytes are stored as human-readable 2-char hex codes. Trailing 0-Bytes may be omitted. Bytes Value Note ------ ---------------------------- 2 bytes Device Class: bit.0 1 = Input Device bit.1 1 = Output Device bit.2 1 = Serial Device bit.3 1 = Block Device (addressable) bit.4 1 = (potential) Controlling Terminal bit.5 1 = 16-bit Device (16-bit io buffers) bit.6 1 = Video Device bit.7 1 = Audio Device bit.8 1 = Keyboard bit.9 1 = Pointer Device (Mouse, Joystick) bit++ reserved. set to 0 1 Byte Requirements: bit.0 1 = requires address lines A4 and A5 bit.1 1 = requires 16-bit Bus bit.2 1 = supports fast block output ( no data hold time after strobe ) bit++ reserved. set to 0 1 Byte IOSPEED = minIOCycleTime[µs]*128 ( e.g. 128 = 1µs ) 1 Byte INTPRIO = interrupt priority = -log2(maxIntLatency[s]) ( 0=1s, 10=1ms, 20=1µs ) Data Types ---------- Data types 0 to 5 are predefined basic types. Data types 6 to 9 may be defined by the driver. Below they are printed with 48 added to the character code, so that value 1 displays as '1' and arrays as 'A' to 'I'. 0 void return value only 1 byte ≥ 8 bit unsigned 2 word ≥ 16 bit unsigned 3 long ≥ 32 bit unsigned 4 reserved 5 reserved 6 user definable struct … "" 9 "" 16 add for array[] --> 'A' .. 'I' text strings are type 'A' (array of int8) err error numbers are int8 bool boolean numbers are int8 and must be 0 or 1 Error Numbers ------------- error numbers are int8: 0 ok 1 parameter error / function not supported 2 io error 3 device not present / device not responding File "D": Structured Data Type Definition ----------------------------------------- Data Value Note ---------- ---------- ---------------- 1 byte {6-9} data type 1 byte cnt number of data members n bytes ITEM[cnt] list with data types: 1 byte {1-9} variable 3 bytes {A-I},nn array[nn] File "A": Global Variables -------------------------- Data Value Note ---------- ---------- ---------------- 1 byte cnt number of global variables: max. 128 n bytes GVAR[cnt] list with data types: 1 byte {1-9} variable 3 bytes {A-I},nn array[nn] Other Files: Interrupt handler, Functions and Procedures -------------------------------------------------------- The file name indicates the procedure name. The interrupt handler is a function too. The interrupt handler must not define local array variables. Data Value Note ---------- ---------- ---------------- 1 byte RVAL return value 1 byte {0-9} variable (arrays not allowed) 1 byte cnt number of arguments n bytes ARGS[cnt] List with data types: 1 byte {1-9} variable 1 byte {A-I} array[] 1 byte cnt number of global variables: max. 128-ARGS n bytes LVARS[cnt] List with data types: 1 byte {1-9} variable 3 bytes {A-I},nn array[nn] n bytes CODE[] bytecode 1 byte $FF bytecode end marker Required Functions ================== All Devices: ------------ err setctl( i8 minor, i8 fu, i16 value ) // set control i16 getctl( i8 minor, i8 fu ) // get state Serial devices: --------------- Serial devices provide cyclic buffers for input and output. The system stores and reads bytes directly from these buffers and moves the read pointer of the input buffer and the write pointer of the output buffer. The driver provides an interrupt function which moves the write pointer of the input buffer and the read pointer of the output buffer. The system can call the INT() handler function directly to restart output after the output buffer had dryed out. After reset the getio() function is called by the system with incrementing minor numbers until the function returns an error code. The iodata struct returned by getio() is defined below. Serial devices may be 8-bit or 16-bit. Accordingly their buffers must be 8-bit or 16-bit. void INT () // interrupt service function void init() // init the device with all its minor devices. // called before any other driver function. iodata getio( i8 minor ) // get (ptr to) input & output buffer setctl/getctl function codes: 00 + set // reset 01 + set/get // set/get serial speed * 100 02 + set/get // set/get HW handshake on/off 03 + set/get // set/get SW handshake on/off struct iodata = { int8 ibuwridx, // input buffer write index int8 iburdidx, // input buffer read index int8|16 ibu[], // input buffer int8 obuwridx, // output buffer write index int8 oburdidx, // output buffer read index int8|16 obu[], // output buffer ... // driver may define additional fields } Block devices: -------------- Block devices provide a function to read or write a sequence of blocks from or to the device. Block devices may be 8-bit or 16-bit. Accordingly they must define io() to take buffers of that size. Block devices hog the CPU while a block i/o is in progress. io() shall only return when all data is read or written or when an error occurs. The driver function can call a special wait() bytecode to release the CPU if it transfers the data with interrupts, else an INT() function is not required. setctl/getctl function codes: 00 + set // reset // 08 + get // get log2(blocksize) ( blocksize must be exp2(n) ) // 09 + get // get total blocks (low) // 10 + get // get total blocks (high) void INT() // interrupt service function void init() // init the device with all its minor devices. // called before any other driver function. err read( int8 minor, int32 startblock, int16 numblocks, int8|16[] data, int16 offset ) err write( int8 minor, int32 startblock, int16 numblocks, int8|16[] data, int16 offset ) int32 numblocks( int8 minor ) // get total blocks int8 log2bsize( int8 minor ) // get log2(blocksize) ( blocksize must be exp2(n) )