#ifndef IOC_H
#define IOC_H

#include <io.h>
#include <sdcard.h>
#include <spi.h>
#include <block_device.h>
#include <boot_tty.h>

//////////////////////////////////////////////////////////////////////////////////////////
//  I/O BLOCK_DEVICE
// The three functions below use the three variables _ioc_lock _ioc_done, 
// and _ioc_status for synchronsation.
// - As the IOC component can be used by several programs running in parallel,
// the _ioc_lock variable guaranties exclusive access to the device.
// The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
// and set _ioc_lock to a non zero value. 
// The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock
// variable until the device is available.
// - When the tranfer is completed, the ISR routine activated by the IOC IRQ
// set the _ioc_done variable to a non-zero value. Possible address errors detected
// by the IOC peripheral are reported by the ISR in the _ioc_status variable.
// The _ioc_completed() function is polling the _ioc_done variable, waiting for
// tranfer conpletion. When the completion is signaled, the _ioc_completed() function
// reset the _ioc_done variable to zero, and releases the _ioc_lock variable.
// 
// In a multi-tasks environment, this polling policy must be replaced by a
// descheduling policy for the requesting process. 
///////////////////////////////////////////////////////////////////////////////////////
//  _ioc_get_lock()
// This blocking function is used by the _ioc_read() and _ioc_write() functions 
// to get _ioc_lock using LL/SC.
///////////////////////////////////////////////////////////////////////////////////////
void _ioc_get_lock();

int _ioc_init();

///////////////////////////////////////////////////////////////////////////////////////
//  _ioc_completed()
// This blocking function cheks completion of an I/O transfer and reports errors.
// It returns 0 if the transfer is successfully completed.
// It returns -1 if an error has been reported.
///////////////////////////////////////////////////////////////////////////////////////
int _ioc_completed();

//////////////////////////////////////////////////////////////////////////////////////
//  _ioc_write()
// Transfer data from a memory buffer to a file on the block_device.
// - lba    : first block index on the disk
// - buffer : base address of the memory buffer
// - count  : number of blocks to be transfered
// The source buffer must be in user address space.
///////////////////////////////////////////////////////////////////////////////////////
int _ioc_write(size_t lba, void* buffer, size_t count);

/**
 *  _ioc_read()
 * 
 * Transfer data from a file on the block device to a memory buffer.
 *
 * \param lba    : first block index on the disk
 * \param buffer : base address of the memory buffer
 * \param count  : number of blocks to be transfered
 *
 * \note This is a blocking function. The function returns once the transfer
 *       has finished
 */
int _ioc_read(size_t lba, void* buffer, size_t count);

#endif

/*
 * vim: tabstop=4 : shiftwidth=4 : expandtab
 */
