RetroArch/gfx/include/userland/interface/vmcs_host/vc_vchi_filesys.c

2471 lines
71 KiB
C

/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#include "vchost.h"
#include "interface/vcos/vcos.h"
#include "interface/vchi/vchi.h"
#include "interface/vchi/common/endian.h"
#include "vc_vchi_filesys.h"
#include "interface/vmcs_host/vc_vchi_fileservice_defs.h"
/******************************************************************************
Global data.
******************************************************************************/
/******************************************************************************
Local types and defines.
******************************************************************************/
typedef enum {
VC_SECTOR_IO_NONE,
VC_SECTOR_IO_READING,
VC_SECTOR_IO_WRITING
} VC_SECTOR_IO_T;
typedef struct {
VCHI_SERVICE_HANDLE_T open_handle;
int32_t num_connections;
//Host->2727
FILESERV_MSG_T fileserv_msg;
//2727->Host XXX
FILESERV_MSG_T vc_msg;
VCOS_THREAD_T filesys_thread;
// used to signal response has arrived
VCOS_EVENT_T response_event;
//we lock each vc_filesys function call
VCOS_MUTEX_T filesys_lock;
//used to signal msg arrivals
VCOS_EVENT_T filesys_msg_avail;
// Outstanding transaction's ID
volatile uint32_t cur_xid;
// Copy of the header code from responses
int32_t resp_code;
int32_t err_no;
char *bulk_buffer;
int32_t initialised;
} FILESYS_SERVICE_T;
static FILESYS_SERVICE_T vc_filesys_client;
/******************************************************************************
Static functions.
******************************************************************************/
//Lock the host state
static __inline int32_t lock_obtain (void) {
int ret = -1;
if(vc_filesys_client.initialised && vcos_mutex_lock(&vc_filesys_client.filesys_lock) == VCOS_SUCCESS) {
vchi_service_use(vc_filesys_client.open_handle);
ret = 0;
}
return ret;
}
//Unlock the host state
static __inline void lock_release (void) {
vcos_assert(vc_filesys_client.initialised);
vchi_service_release(vc_filesys_client.open_handle);
vcos_mutex_unlock(&vc_filesys_client.filesys_lock);
}
// File Service VCHI functions
static int vchi_msg_stub(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len );
static int vchi_msg_stub_noblock(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len);
static int vc_fs_message_handler( FILESERV_MSG_T* msg, uint32_t nbytes );
static void *filesys_task_func(void *arg);
static void filesys_callback( void *callback_param, VCHI_CALLBACK_REASON_T reason, void *msg_handle );
#ifdef PRINTF
#ifdef WIN32
#define printf tprintf
#endif
static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
struct file_service_msg_body const * body);
#endif
static int fs_host_direntbytestream_create(struct dirent *d, void *buffer);
static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer);
/*---------------------------------------------------------------------------*/
/******************************************************************************
NAME
vc_filesys_init
SYNOPSIS
vc_filesys_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
FUNCTION
Initialise the file system for use. A negative return value
indicates failure (which may mean it has not been started on VideoCore).
RETURNS
int
******************************************************************************/
int vc_vchi_filesys_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
{
int32_t success = 0;
SERVICE_CREATION_T filesys_parameters;
VCOS_THREAD_ATTR_T attrs;
VCOS_STATUS_T status;
// record the number of connections
memset( &vc_filesys_client, 0, sizeof(FILESYS_SERVICE_T) );
vc_filesys_client.num_connections = num_connections;
if(!vcos_verify(vc_filesys_client.num_connections < 2))
return -1;
status = vcos_mutex_create(&vc_filesys_client.filesys_lock, "HFilesys");
vcos_assert(status == VCOS_SUCCESS);
status = vcos_event_create(&vc_filesys_client.filesys_msg_avail, "HFilesys");
vcos_assert(status == VCOS_SUCCESS);
//create sema used to signal cmd response has arrived
status = vcos_event_create(&vc_filesys_client.response_event, "HFilesys");
vcos_assert(status == VCOS_SUCCESS);
vc_filesys_client.bulk_buffer = vcos_malloc_aligned(FILESERV_MAX_BULK, 16, "HFilesys bulk_recv");
vc_filesys_client.cur_xid = 0;
memset(&filesys_parameters, 0, sizeof(filesys_parameters));
filesys_parameters.service_id = FILESERV_4CC; // 4cc service code
filesys_parameters.connection = connections[0]; // passed in fn ptrs
filesys_parameters.rx_fifo_size = 0; // rx fifo size (unused)
filesys_parameters.tx_fifo_size = 0; // tx fifo size (unused)
filesys_parameters.callback = &filesys_callback;
filesys_parameters.callback_param = &vc_filesys_client.filesys_msg_avail;
filesys_parameters.want_unaligned_bulk_rx = 0;
filesys_parameters.want_unaligned_bulk_tx = 0;
filesys_parameters.want_crc = 0;
filesys_parameters.version.version = VC_FILESERV_VER;
filesys_parameters.version.version_min = VC_FILESERV_VER;
success = vchi_service_open( initialise_instance, &filesys_parameters, &vc_filesys_client.open_handle );
vcos_assert( success == 0 );
vcos_thread_attr_init(&attrs);
vcos_thread_attr_setstacksize(&attrs, 4000);
vcos_thread_attr_settimeslice(&attrs, 1);
vc_filesys_client.initialised = 1;
status = vcos_thread_create(&vc_filesys_client.filesys_thread, "HFilesys", &attrs, filesys_task_func, NULL);
vcos_assert(status == VCOS_SUCCESS);
/* Not using service immediately - release videocore */
vchi_service_release(vc_filesys_client.open_handle);
return (int)success;
}
static void *filesys_task_func(void *arg)
{
int32_t success;
uint32_t msg_len;
(void)arg;
vc_hostfs_init();
while(1) {
// wait for the semaphore to say that there is a message
if (vcos_event_wait(&vc_filesys_client.filesys_msg_avail) != VCOS_SUCCESS || vc_filesys_client.initialised == 0)
break;
vchi_service_use(vc_filesys_client.open_handle);
// read the message - should we really "peek" this
while (1) {
success = vchi_msg_dequeue(vc_filesys_client.open_handle, &vc_filesys_client.vc_msg,
sizeof(vc_filesys_client.vc_msg), &msg_len, VCHI_FLAGS_NONE);
if (!success)
break;
/* coverity[tainted_string_argument] */
success = (int32_t) vc_fs_message_handler(&vc_filesys_client.vc_msg, msg_len);
(void)success;
}
vchi_service_release(vc_filesys_client.open_handle);
}
return 0;
}
/******************************************************************************
NAME
filesys_callback
SYNOPSIS
void filesys_callback( void *callback_param,
const VCHI_CALLBACK_REASON_T reason,
const void *msg_handle )
FUNCTION
VCHI callback
RETURNS
int
******************************************************************************/
static void filesys_callback( void *callback_param,
const VCHI_CALLBACK_REASON_T reason,
void *msg_handle )
{
(void)msg_handle;
switch( reason ) {
case VCHI_CALLBACK_MSG_AVAILABLE:
{
VCOS_EVENT_T *event = (VCOS_EVENT_T *) callback_param;
if(event)
vcos_event_signal(event);
}
break;
case VCHI_CALLBACK_BULK_RECEIVED:
break;
case VCHI_CALLBACK_BULK_SENT:
break;
default:
return;
}
}
/******************************************************************************
NAME
vc_filesys_stop
SYNOPSIS
void vc_filesys_stop()
FUNCTION
This tells us that the file system service has stopped, thereby preventing
any of the functions from doing anything.
RETURNS
void
******************************************************************************/
void vc_filesys_stop ()
{
int32_t result;
void *dummy;
if(lock_obtain() != 0)
return;
result = vchi_service_close(vc_filesys_client.open_handle);
vcos_assert(result == 0);
vc_filesys_client.initialised = 0;
vcos_event_signal(&vc_filesys_client.filesys_msg_avail);
vcos_thread_join(&vc_filesys_client.filesys_thread, &dummy);
vcos_event_delete(&vc_filesys_client.filesys_msg_avail);
vcos_event_delete(&vc_filesys_client.response_event);
vcos_mutex_delete(&vc_filesys_client.filesys_lock);
if(vc_filesys_client.bulk_buffer)
vcos_free(vc_filesys_client.bulk_buffer);
}
/******************************************************************************
NAME
vc_filesys_single_param
SYNOPSIS
int vc_filesys_single_param(uint32_t param, uint32_t fn)
FUNCTION
Utility function for implementing filesys methods
RETURNS
void
******************************************************************************/
static int vc_filesys_single_param(uint32_t param, uint32_t fn)
{
int success = -1;
if(lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = param;
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, fn, 4) == FILESERV_RESP_OK)
success = 0;
lock_release();
}
return success;
}
/******************************************************************************
NAME
vc_filesys_single_string
SYNOPSIS
int vc_filesys_single_string(uint32_t param, const char *str, uint32_t fn, int return_param)
FUNCTION
Utility function for implementing filesys methods
RETURNS
void
******************************************************************************/
static int vc_filesys_single_string(uint32_t param, const char *str, uint32_t fn, int return_param)
{
int ret = -1;
int len = strlen(str);
if(len < FILESERV_MAX_DATA && lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = param;
/* coverity[buffer_size_warning] - the length of str has already been checked */
strncpy((char*)vc_filesys_client.fileserv_msg.data, str, FILESERV_MAX_DATA);
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, fn, len+1+16) == FILESERV_RESP_OK)
{
if(return_param)
ret = (int) vc_filesys_client.fileserv_msg.params[0];
else
ret = 0;
}
lock_release();
}
return ret;
}
/* Standard UNIX low-level library functions (declared in unistd.h) */
/******************************************************************************
NAME
vc_filesys_close
SYNOPSIS
int vc_filesys_close(int fildes)
FUNCTION
Deallocates the file descriptor to a file.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_close(int fildes)
{
return vc_filesys_single_param((uint32_t) fildes, VC_FILESYS_CLOSE);
}
/******************************************************************************
NAME
vc_filesys_lseek
SYNOPSIS
long vc_filesys_lseek(int fildes, long offset, int whence)
FUNCTION
Sets the file pointer associated with the open file specified by fildes.
RETURNS
Successful completion: offset
Otherwise: -1
******************************************************************************/
long vc_filesys_lseek(int fildes, long offset, int whence)
{
long set = -1;
if(lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
vc_filesys_client.fileserv_msg.params[1] = (uint32_t) offset;
vc_filesys_client.fileserv_msg.params[2] = (uint32_t) whence;
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_LSEEK, 12) == FILESERV_RESP_OK)
set = (long) vc_filesys_client.fileserv_msg.params[0];
lock_release();
}
return set;
}
/******************************************************************************
NAME
vc_filesys_lseek64
SYNOPSIS
int64_t vc_filesys_lseek64(int fildes, int64_t offset, int whence)
FUNCTION
Sets the file pointer associated with the open file specified by fildes.
RETURNS
Successful completion: file pointer value
Otherwise: -1
******************************************************************************/
int64_t vc_filesys_lseek64(int fildes, int64_t offset, int whence)
{
int64_t set = -1;
if(lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
vc_filesys_client.fileserv_msg.params[1] = (uint32_t) offset; // LSB
vc_filesys_client.fileserv_msg.params[2] = (uint32_t)(offset >> 32); // MSB
vc_filesys_client.fileserv_msg.params[3] = (uint32_t) whence;
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_LSEEK64, 16) == FILESERV_RESP_OK)
{
set = vc_filesys_client.fileserv_msg.params[0];
set += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
}
lock_release();
}
return set;
}
/******************************************************************************
NAME
vc_filesys_mount
SYNOPSIS
int vc_filesys_mount(const char *device, const char *mountpoint, const char *options)
FUNCTION
Mounts a filesystem at a given location
RETURNS
Successful completion: 0
******************************************************************************/
int vc_filesys_mount(const char *device, const char *mountpoint, const char *options)
{
int set = -1, len;
int a = strlen(device);
int b = strlen(mountpoint);
int c = strlen(options);
if(a + b + c + 3 < FILESERV_MAX_DATA && lock_obtain() == 0)
{
char *str = (char *) vc_filesys_client.fileserv_msg.data;
memcpy(str, device, a);
str[a] = 0;
memcpy(str+a+1, mountpoint, b);
str[a+1+b] = 0;
memcpy(str+a+b+2, options, c);
str[a+b+c+2] = 0;
len = a + b + c + 3 + (int)(((FILESERV_MSG_T *)0)->data);
len = ((len + (VCHI_BULK_GRANULARITY-1)) & ~(VCHI_BULK_GRANULARITY-1)) + VCHI_BULK_GRANULARITY;
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_MOUNT, len) == FILESERV_RESP_OK)
set = (int) vc_filesys_client.fileserv_msg.params[0];
lock_release();
}
return set;
}
/******************************************************************************
NAME
vc_filesys_umount
SYNOPSIS
int vc_filesys_mount(const char *mountpoint)
FUNCTION
Un-mounts a removable device from the location that it has been mounted
to earlier in the session
RETURNS
Successful completion: 0
******************************************************************************/
int vc_filesys_umount(const char *mountpoint)
{
return vc_filesys_single_string(0, mountpoint, VC_FILESYS_UMOUNT, 1);
}
/******************************************************************************
NAME
vc_filesys_open
SYNOPSIS
int vc_filesys_open(const char *path, int vc_oflag)
FUNCTION
Establishes a connection between a file and a file descriptor.
RETURNS
Successful completion: file descriptor
Otherwise: -1
******************************************************************************/
int vc_filesys_open(const char *path, int vc_oflag)
{
return vc_filesys_single_string((uint32_t) vc_oflag, path, VC_FILESYS_OPEN, 1);
}
/******************************************************************************
NAME
vc_filesys_read
SYNOPSIS
int vc_filesys_read(int fildes, void *buf, unsigned int nbyte)
FUNCTION
Attempts to read nbyte bytes from the file associated with the file
descriptor, fildes, into the buffer pointed to by buf.
RETURNS
Successful completion: number of bytes read
Otherwise: -1
******************************************************************************/
/******************************************************************************
FUNCTION
RETURNS
Successful completion: the number of bytes received
Otherwise negative error code
******************************************************************************/
static int vc_vchi_msg_bulk_read(FILESERV_MSG_T* msg, uint16_t cmd_id, uint32_t transfer_len, uint8_t* recv_addr )
{
uint32_t i;
int msg_len;
uint32_t host_align_bytes;
uint32_t num_bytes_read;
int32_t success;
//this is current file_io_buffer size so assuming never more than this
//otherwise we will split the read into chunks
if(!vcos_verify(transfer_len <= FILESERV_MAX_BULK))
return -1;
//number of bytes required to align recv_addr
host_align_bytes = VCHI_BULK_ALIGN_NBYTES(recv_addr);
i = vc_filesys_client.cur_xid + 1;
i &= 0x7fffffffUL;
vc_filesys_client.cur_xid = i;
msg->xid = vc_filesys_client.cur_xid;
//fill in cmd id: VC_FILESYS_READ etc
msg->cmd_code = cmd_id;
msg->params[2] = transfer_len;
msg->params[3] = host_align_bytes;
//24 comes from the static size of FILESERV_MSG_T
msg_len = 24;
if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
return -1;
//wait to receive response
if(vcos_event_wait(&vc_filesys_client.response_event) != VCOS_SUCCESS || msg->cmd_code == FILESERV_RESP_ERROR)
return -1;
//total bytes read
num_bytes_read = msg->params[0];
if(!vcos_verify(num_bytes_read <= FILESERV_MAX_BULK))
return -1;
//everything is in msg->data
if(msg->cmd_code == FILESERV_RESP_OK) {
if(!vcos_verify(num_bytes_read <= FILESERV_MAX_DATA))
return -1;
memcpy(recv_addr, msg->data, num_bytes_read);
return (int) num_bytes_read;
}
// Make this code conditional to stop Coverity complaining about dead code
#if VCHI_BULK_ALIGN > 1
//copy host_align_bytes bytes to recv_addr, now ready for bulk
if(host_align_bytes) {
memcpy(recv_addr, msg->data, host_align_bytes);
recv_addr += host_align_bytes;
transfer_len -= host_align_bytes;
}
#endif
//receive bulk from host
if(msg->cmd_code == FILESERV_BULK_WRITE){
//number of end bytes
uint32_t end_bytes = msg->params[1];
//calculate what portion of read transfer by bulk
uint32_t bulk_bytes = (num_bytes_read-host_align_bytes-end_bytes);
success = vchi_bulk_queue_receive(vc_filesys_client.open_handle,
recv_addr,
bulk_bytes,
VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
NULL );
if(!vcos_verify(success == 0))
return -1;
recv_addr+=bulk_bytes;
//copy any left over end bytes from original msg
if(end_bytes)
memcpy(recv_addr, &msg->data[host_align_bytes], end_bytes);
}
else {
return -1;
}
return (int) num_bytes_read;
}
int vc_filesys_read(int fildes, void *buf, unsigned int nbyte)
{
int bulk_bytes = 0;
int actual_read = 0;
int total_byte = 0;
uint8_t* ptr = (uint8_t*)buf;
if (nbyte == 0) {
return 0;
}
if(lock_obtain() == 0)
{
do {
bulk_bytes = nbyte > FILESERV_MAX_BULK ? FILESERV_MAX_BULK : nbyte;
//we overwrite the response here so fill in data again
vc_filesys_client.fileserv_msg.params[0] = (uint32_t)fildes;
vc_filesys_client.fileserv_msg.params[1] = 0xffffffffU; // offset: use -1 to indicate no offset
actual_read = vc_vchi_msg_bulk_read(&vc_filesys_client.fileserv_msg , VC_FILESYS_READ, (uint32_t)bulk_bytes, (uint8_t*)ptr);
if(bulk_bytes != actual_read) {
if(actual_read < 0)
total_byte = -1;
else
total_byte += actual_read;
//exit loop
break;
}
ptr+=bulk_bytes;
nbyte -= actual_read;
total_byte += actual_read;
}while(nbyte > 0);
lock_release();
}
return total_byte;
}
/******************************************************************************
NAME
vc_filesys_write
SYNOPSIS
int vc_filesys_write(int fildes, const void *buf, unsigned int nbyte)
FUNCTION
Attempts to write nbyte bytes from the buffer pointed to by buf to file
associated with the file descriptor, fildes.
RETURNS
Successful completion: number of bytes written
Otherwise: -1
******************************************************************************/
/******************************************************************************
FUNCTION
RETURNS
Successful completion: the number of bytes received
Otherwise negative error code
******************************************************************************/
static int vc_vchi_msg_bulk_write(FILESERV_MSG_T* msg, uint16_t cmd_id, uint32_t transfer_len, uint8_t* send_addr )
{
uint32_t i;
int msg_len;
uint32_t align_bytes = 0;
uint32_t bulk_end_bytes = 0;
uint32_t bulk_bytes = 0;
int num_bytes_written = -1;
//this is current file_io_buffer size so assuming never more than this
//otherwise we will split the read into chunks
if(!vcos_verify(transfer_len <= FILESERV_MAX_BULK))
return -1;
i = vc_filesys_client.cur_xid + 1;
i &= 0x7fffffffUL;
vc_filesys_client.cur_xid = i;
msg->xid = vc_filesys_client.cur_xid;
//fill in cmd id VC_FILESYS_OPEN etc
msg->cmd_code = cmd_id;
msg->params[2] = transfer_len;
//24 comes from the static size of FILESERV_MSG_T
msg_len = 24;
//put it all in one msg
if(transfer_len <= FILESERV_MAX_DATA) {
memcpy(msg->data, send_addr, transfer_len);
msg->params[3] = 0;
msg_len += transfer_len;
//send request to write to host
if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
return -1;
// wait to receive response
if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS &&
msg->cmd_code != FILESERV_RESP_ERROR && msg->params[0] == transfer_len)
{
//vc_fs_message_handler copies resp into outgoing msg struct
num_bytes_written = (int)msg->params[0];
}
}
else {
//required to make send_addr for bulk
align_bytes = VCHI_BULK_ALIGN_NBYTES(send_addr);
// Make this code conditional to stop Coverity complaining about dead code
#if VCHI_BULK_ALIGN > 1
//copy vc_align bytes to msg->data, send_addr ready for bulk
if(align_bytes) {
msg->params[3] = align_bytes;
memcpy(msg->data, send_addr, align_bytes);
transfer_len -= align_bytes;
send_addr += align_bytes;
msg_len += align_bytes;
}
else
#endif
msg->params[3] = 0;
// need to ensure we have the appropriate alignment
bulk_bytes = (transfer_len)&(~(VCHI_BULK_GRANULARITY-1));
bulk_end_bytes = transfer_len-bulk_bytes;
if(bulk_end_bytes) {
memcpy(msg->data+align_bytes, send_addr+bulk_bytes, bulk_end_bytes);
msg_len += bulk_end_bytes;
}
//send request to write to host
if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
return -1;
//send bulk VCHI_FLAGS_BLOCK_UNTIL_QUEUED is ok because we wait for response msg with actual length written
if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle,
send_addr,
bulk_bytes,
VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
NULL ) != 0)
return -1;
// wait to receive response sent by filsys_task_func
if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && msg->cmd_code == FILESERV_BULK_READ)
num_bytes_written = (int)msg->params[0];
}
return num_bytes_written;
}
int vc_filesys_write(int fildes, const void *buf, unsigned int nbyte)
{
int num_wrt = 0;
int bulk_bytes = 0;
int actual_written = 0;
uint8_t *ptr = (uint8_t*) buf;
if (nbyte == 0) {
return 0;
}
if(lock_obtain() == 0)
{
//will split the read into 4K chunks based on vc fwrite buffer size array size
//we will make this more dynamic later
do {
bulk_bytes = nbyte > FILESERV_MAX_BULK ? FILESERV_MAX_BULK : nbyte;
//we overwrite the response here so fill in data again
vc_filesys_client.fileserv_msg.params[0] = (uint32_t)fildes;
vc_filesys_client.fileserv_msg.params[1] = 0xffffffffU; // offset: use -1 to indicate no offset
actual_written = vc_vchi_msg_bulk_write(&vc_filesys_client.fileserv_msg , VC_FILESYS_WRITE, (uint32_t)bulk_bytes, (uint8_t*)ptr);
if(bulk_bytes != actual_written) {
if(actual_written < 0)
num_wrt = -1;
else
num_wrt += actual_written;
break;
}
ptr+=bulk_bytes;
nbyte -= actual_written;
num_wrt += actual_written;
}while(nbyte > 0);
lock_release();
}
return num_wrt;
}
/* Directory management functions */
/******************************************************************************
NAME
vc_filesys_closedir
SYNOPSIS
int vc_filesys_closedir(void *dhandle)
FUNCTION
Ends a directory list iteration.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_closedir(void *dhandle)
{
return vc_filesys_single_param((uint32_t)dhandle, VC_FILESYS_CLOSEDIR);
}
/******************************************************************************
NAME
vc_filesys_format
SYNOPSIS
int vc_filesys_format(const char *path)
FUNCTION
Formats the physical file system that contains path.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_format(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_FORMAT, 0);
}
/******************************************************************************
NAME
vc_filesys_freespace
SYNOPSIS
int vc_filesys_freespace(const char *path)
FUNCTION
Returns the amount of free space on the physical file system that contains
path.
RETURNS
Successful completion: free space
Otherwise: -1
******************************************************************************/
int vc_filesys_freespace(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_FREESPACE, 1);
}
/******************************************************************************
NAME
vc_filesys_freespace64
SYNOPSIS
int64_t vc_filesys_freespace64(const char *path)
FUNCTION
Returns the amount of free space on the physical file system that contains
path.
RETURNS
Successful completion: free space
Otherwise: -1
******************************************************************************/
int64_t vc_filesys_freespace64(const char *path)
{
int64_t freespace = -1LL;
if(lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_FREESPACE64,
(int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
{
freespace = vc_filesys_client.fileserv_msg.params[0];
freespace += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
}
lock_release();
}
return freespace;
}
/******************************************************************************
NAME
vc_filesys_get_attr
SYNOPSIS
int vc_filesys_get_attr(const char *path, fattributes_t *attr)
FUNCTION
Gets the file/directory attributes.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_get_attr(const char *path, fattributes_t *attr)
{
int success = -1;
if(lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_GET_ATTR,
(int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
{
success = 0;
*attr = (fattributes_t) vc_filesys_client.fileserv_msg.params[0];
}
lock_release();
}
return success;
}
/******************************************************************************
NAME
vc_filesys_fstat
SYNOPSIS
int64_t vc_filesys_fstat(int fildes, FSTAT_T *buf)
FUNCTION
Returns the file stat info structure for the specified file.
This structure includes date and size info.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_fstat(int fildes, FSTAT_T *buf)
{
int success = -1;
if (buf != NULL && lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
if ( vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_FSTAT, 4) == FILESERV_RESP_OK )
{
buf->st_size = (int64_t)vc_filesys_client.fileserv_msg.params[0]; // LSB
buf->st_size |= (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32; // MSB
buf->st_modtime = (uint32_t)vc_filesys_client.fileserv_msg.params[2];
// there's room for expansion here to pass across more elements of the structure if required...
success = 0;
}
lock_release();
}
return success;
}
/******************************************************************************
NAME
vc_filesys_mkdir
SYNOPSIS
int vc_filesys_mkdir(const char *path)
FUNCTION
Creates a new directory named by the pathname pointed to by path.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_mkdir(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_MKDIR, 0);
}
/******************************************************************************
NAME
vc_filesys_opendir
SYNOPSIS
void *vc_filesys_opendir(const char *dirname)
FUNCTION
Starts a directory list iteration.
RETURNS
Successful completion: dhandle (pointer)
Otherwise: NULL
******************************************************************************/
void *vc_filesys_opendir(const char *dirname)
{
return (void *) vc_filesys_single_string(0, dirname, VC_FILESYS_OPENDIR, 1);
}
/******************************************************************************
NAME
vc_filesys_dirsize
SYNOPSIS
int vc_filesys_dirsize(const char *path)
FUNCTION
Look through the specified directory tree and sum the file sizes.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int64_t vc_filesys_dirsize(const char *path, uint32_t *num_files, uint32_t *num_dirs)
{
int64_t ret = -1;
if(lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
// FIXME: Should probably use a non-blocking call here since it may take a
// long time to do the operation...
if ( vchi_msg_stub(&vc_filesys_client.fileserv_msg,
VC_FILESYS_DIRSIZE,
(int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK )
{
ret = vc_filesys_client.fileserv_msg.params[0];
ret += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
if (num_files)
*num_files = vc_filesys_client.fileserv_msg.params[2];
if (num_dirs)
*num_dirs = vc_filesys_client.fileserv_msg.params[3];
}
lock_release();
}
return ret;
}
/******************************************************************************
NAME
vc_filesys_readdir_r
SYNOPSIS
struct dirent *vc_filesys_readdir_r(void *dhandle, struct dirent *result)
FUNCTION
Fills in the passed result structure with details of the directory entry
at the current psition in the directory stream specified by the argument
dhandle, and positions the directory stream at the next entry.
RETURNS
Successful completion: result
End of directory stream: NULL
******************************************************************************/
struct dirent *vc_filesys_readdir_r(void *dhandle, struct dirent *result)
{
struct dirent *ret = NULL;
if(lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = (uint32_t)dhandle;
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_READDIR, 4) == FILESERV_RESP_OK)
{
fs_host_direntbytestream_interp(result, (void *)vc_filesys_client.fileserv_msg.data);
ret = result;
}
lock_release();
}
return ret;
}
/******************************************************************************
NAME
vc_filesys_remove
SYNOPSIS
int vc_filesys_remove(const char *path)
FUNCTION
Removes a file or a directory. A directory must be empty before it can be
deleted.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_remove(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_REMOVE, 0);
}
/******************************************************************************
NAME
vc_filesys_rename
SYNOPSIS
int vc_filesys_rename(const char *oldfile, const char *newfile)
FUNCTION
Changes the name of a file. The old and new pathnames must be on the same
physical file system.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_rename(const char *oldfile, const char *newfile)
{
int a, b, success = -1;
// Ensure the pathnames aren't too long
if ((a = strlen(oldfile)) < FS_MAX_PATH && (b = strlen(newfile)) < FS_MAX_PATH && lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, oldfile, FS_MAX_PATH);
strncpy((char *)&vc_filesys_client.fileserv_msg.data[a+1], newfile, FS_MAX_PATH);
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_RENAME, 16+a+1+b+1) == FILESERV_RESP_OK)
success = 0;
lock_release();
}
return success;
}
/******************************************************************************
NAME
vc_filesys_reset
SYNOPSIS
int vc_filesys_reset()
FUNCTION
Send a vc_FILESYS_RESET command. This will return immediately.
RETURNS
Successful completion: FILESERV_RESP_OK
Otherwise: -
******************************************************************************/
int vc_filesys_reset()
{
return vc_filesys_single_param(0, VC_FILESYS_RESET);
}
/******************************************************************************
NAME
vc_filesys_set_attr
SYNOPSIS
int vc_filesys_set_attr(const char *path, fattributes_t attr)
FUNCTION
Sets file/directory attributes.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_set_attr(const char *path, fattributes_t attr)
{
return vc_filesys_single_string((uint32_t) attr, path, VC_FILESYS_SET_ATTR, 0);
}
/******************************************************************************
NAME
vc_filesys_setend
SYNOPSIS
int vc_filesys_setend(int fildes)
FUNCTION
Truncates file at current position.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_setend(int fildes)
{
return vc_filesys_single_param((uint32_t) fildes, VC_FILESYS_SETEND);
}
/******************************************************************************
NAME
vc_filesys_scandisk
SYNOPSIS
void vc_filesys_scandisk(const char *path)
FUNCTION
Truncates file at current position.
RETURNS
-
******************************************************************************/
void vc_filesys_scandisk(const char *path)
{
vc_filesys_single_string(0, path, VC_FILESYS_SCANDISK, 0);
return;
}
/******************************************************************************
NAME
vc_filesys_chkdsk
SYNOPSIS
int vc_filesys_chkdsk(const char *path, int fix_errors)
FUNCTION
Truncates file at current position.
RETURNS
-
******************************************************************************/
int vc_filesys_chkdsk(const char *path, int fix_errors)
{
return vc_filesys_single_string(fix_errors, path, VC_FILESYS_CHKDSK, 1);
}
/******************************************************************************
NAME
vc_filesys_size
SYNOPSIS
int vc_filesys_size(const char *path)
FUNCTION
return size of file
RETURNS
-
******************************************************************************/
int vc_filesys_size(const char *path)
{
int fd;
int end_pos = 0;
int success = -1;
if((fd = vc_filesys_open(path, VC_O_RDONLY)) == 0)
{
end_pos = vc_filesys_lseek(fd, 0, SEEK_END);
success = vc_filesys_close(fd);
(void)success;
}
return end_pos;
}
/******************************************************************************
NAME
vc_filesys_totalspace
SYNOPSIS
int vc_filesys_totalspace(const char *path)
FUNCTION
Returns the total amount of space on the physical file system that contains
path.
RETURNS
Successful completion: total space
Otherwise: -1
******************************************************************************/
int vc_filesys_totalspace(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_TOTALSPACE, 1);
}
/******************************************************************************
NAME
vc_filesys_totalspace64
SYNOPSIS
int64_t vc_filesys_totalspace64(const char *path)
FUNCTION
Returns the total amount of space on the physical file system that contains
path.
RETURNS
Successful completion: total space
Otherwise: -1
******************************************************************************/
int64_t vc_filesys_totalspace64(const char *path)
{
int64_t totalspace = -1LL;
if(lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_TOTALSPACE64,
(int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
{
totalspace = vc_filesys_client.fileserv_msg.params[0];
totalspace += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
}
lock_release();
}
return totalspace;
}
/******************************************************************************
NAME
vc_filesys_diskwritable
SYNOPSIS
int vc_filesys_diskwritable(const char *path)
FUNCTION
Return whether the named disk is writable.
RETURNS
Successful completion: 1 (disk writable) or 0 (disk not writable)
Otherwise: -1
******************************************************************************/
int vc_filesys_diskwritable(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_DISKWRITABLE, 1);
}
/******************************************************************************
NAME
vc_filesys_fstype
SYNOPSIS
int vc_filesys_fstype(const char *path)
FUNCTION
Return the filesystem type of the named disk.
RETURNS
Successful completion: disk type (see vc_fileservice_defs.h)
Otherwise: -1
******************************************************************************/
int vc_filesys_fstype(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_FSTYPE, 1);
}
/******************************************************************************
NAME
vc_filesys_open_disk_raw
SYNOPSIS
int vc_filesys_open_disk_raw(const char *path)
FUNCTION
Open disk for access in raw mode.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_open_disk_raw(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_OPEN_DISK_RAW, 1);
}
/******************************************************************************
NAME
vc_filesys_close_disk_raw
SYNOPSIS
int vc_filesys_close_disk_raw(const char *path)
FUNCTION
Close disk from access in raw mode.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_close_disk_raw(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_CLOSE_DISK_RAW, 1);
}
/******************************************************************************
NAME
vc_filesys_open_disk
SYNOPSIS
int vc_filesys_open_disk(const char *path)
FUNCTION
Open disk for normal access.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_open_disk(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_OPEN_DISK, 1);
}
/******************************************************************************
NAME
vc_filesys_close_disk
SYNOPSIS
int vc_filesys_close_disk(const char *path)
FUNCTION
Close disk from normal access.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_close_disk(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_CLOSE_DISK, 1);
}
/******************************************************************************
NAME
vc_filesys_numsectors
SYNOPSIS
int vc_filesys_numsectors(const char *path)
FUNCTION
Return number of sectors on disk
RETURNS
Successful completion: greater than 0
Otherwise: -1
******************************************************************************/
int vc_filesys_numsectors(const char *path)
{
return vc_filesys_single_string(0, path, VC_FILESYS_NUMSECTORS, 1);
}
/******************************************************************************
NAME
vc_filesys_read_sectors
SYNOPSIS
int vc_filesys_read_sectors(const char *path, uint32_t sector_num, char *buffer, uint32_t num_sectors)
FUNCTION
Start streaming sectors from 2727
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
int vc_filesys_read_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_read)
{
#if VCHI_BULK_ALIGN > 1
uint32_t align_bytes = 0;
#endif
char* bulk_addr = sectors;
int len;
int ret = -1;
if((len = (int)strlen(path)) < FS_MAX_PATH && lock_obtain() == 0)
{
strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
vc_filesys_client.fileserv_msg.params[0] = sector_num;
vc_filesys_client.fileserv_msg.params[1] = num_sectors;
#if VCHI_BULK_ALIGN > 1
//required to make buffer aligned for bulk
align_bytes = VCHI_BULK_ALIGN_NBYTES(sectors);
#endif
//note for read we are currently doing memcpy on host to tell 2727 align is 0
vc_filesys_client.fileserv_msg.params[2] = 0;
//we send read request
if (vchi_msg_stub_noblock(&vc_filesys_client.fileserv_msg, VC_FILESYS_READ_SECTORS, 16+len+1) == 0)
{
while(num_sectors)
{
uint32_t bulk_sectors = (num_sectors > FILESERV_MAX_BULK_SECTOR) ? (uint32_t)FILESERV_MAX_BULK_SECTOR : num_sectors;
if(vchi_bulk_queue_receive( vc_filesys_client.open_handle,
#if VCHI_BULK_ALIGN > 1
align_bytes ? vc_filesys_client.bulk_buffer : bulk_addr,
#else
bulk_addr,
#endif
(bulk_sectors*FILESERV_SECTOR_LENGTH), VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, NULL) != 0)
break;
#if VCHI_BULK_ALIGN > 1
if(align_bytes) {
//this is bad but will do for now..
memcpy( bulk_addr, vc_filesys_client.bulk_buffer, (bulk_sectors*FILESERV_SECTOR_LENGTH));
}
#endif
bulk_addr += (bulk_sectors*FILESERV_SECTOR_LENGTH);
num_sectors -= bulk_sectors;
}
// now wait to receive resp from original msg...
if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && vc_filesys_client.fileserv_msg.cmd_code == FILESERV_RESP_OK)
{
*sectors_read = vc_filesys_client.fileserv_msg.params[0];
ret = 0;
}
else
{
//error code in [0]
*sectors_read = vc_filesys_client.fileserv_msg.params[1];
ret = vc_filesys_client.fileserv_msg.params[0];
}
}
lock_release();
}
return ret;
}
/******************************************************************************
NAME
vc_filesys_write_sectors
SYNOPSIS
int vc_filesys_write_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_written)
FUNCTION
Start streaming sectors to 2727
RETURNS
Successful completion: 0
Otherwise: -error code
******************************************************************************/
int vc_filesys_write_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_written)
{
uint32_t align_bytes = 0;
char* bulk_addr = sectors;
int len;
int ret = -1;
len = (int) strlen(path);
if((len = (int) strlen(path)) < FS_MAX_PATH && lock_obtain() == 0)
{
vc_filesys_client.fileserv_msg.params[0] = sector_num;
vc_filesys_client.fileserv_msg.params[1] = num_sectors;
//required to make buffer aligned for bulk
align_bytes = ((unsigned long)sectors & (VCHI_BULK_ALIGN-1));
vc_filesys_client.fileserv_msg.params[2] = align_bytes;
//copy path at end of any alignbytes
strncpy(((char *)vc_filesys_client.fileserv_msg.data), path, FS_MAX_PATH);
//we send write request
if (vchi_msg_stub_noblock(&vc_filesys_client.fileserv_msg, VC_FILESYS_WRITE_SECTORS, 16+len+1) == 0)
{
if(align_bytes) {
//note we are cheating and going backward to make addr aligned and sending more data...
bulk_addr -= align_bytes;
}
while(num_sectors) {
uint32_t bulk_sectors = (num_sectors > FILESERV_MAX_BULK_SECTOR) ? (uint32_t)FILESERV_MAX_BULK_SECTOR : num_sectors;
//we send some extra data at the start
if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle, bulk_addr,
VCHI_BULK_ROUND_UP((bulk_sectors*FILESERV_SECTOR_LENGTH)+align_bytes),
VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, NULL) != 0)
break;
//go to next ALIGNED address
bulk_addr += FILESERV_MAX_BULK;
num_sectors -= bulk_sectors;
}
// now wait to receive resp from original msg...
if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && vc_filesys_client.fileserv_msg.cmd_code == FILESERV_RESP_OK)
{
*sectors_written = vc_filesys_client.fileserv_msg.params[0];
ret = 0;
}
else
{
//error code in [0]
*sectors_written = vc_filesys_client.fileserv_msg.params[1];
ret = vc_filesys_client.fileserv_msg.params[0];
}
}
lock_release();
}
return ret;
}
/******************************************************************************
NAME
vc_filesys_errno
SYNOPSIS
int vc_filesys_errno(void)
FUNCTION
Returns the error code of the last file system error that occurred.
RETURNS
Error code
******************************************************************************/
int vc_filesys_errno(void)
{
return (int) vc_filesys_client.err_no;
}
/* File Service Message FIFO functions */
/******************************************************************************
NAME
vchi_msg_stub
SYNOPSIS
static int vc_fs_stub(int verb, int ext_len)
FUNCTION
Generates a request and sends it to the co-processor. It then suspends
until it receives a reply from the host. The calling task must hold
the filesys_lock.
RETURNS
Successful completion: Response code of reply
Otherwise: -
******************************************************************************/
static int vchi_msg_stub(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len )
{
int ret = -1;
vchi_msg_stub_noblock(msg, cmd_id, msg_len);
// wait to receive response
if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS)
ret = (int) msg->cmd_code;
return ret;
}
static int vchi_msg_stub_noblock(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len)
{
uint32_t i;
if(!vcos_verify(msg_len <= VCHI_MAX_MSG_SIZE))
return -1;
//will get changed by response from command
vc_filesys_client.resp_code = FILESERV_RESP_ERROR;
//the top bit is used for host/vc
i = vc_filesys_client.cur_xid + 1;
i &= 0x7fffffffUL;
vc_filesys_client.cur_xid = i;
//fill in transaction id, used for response identification
vchi_writebuf_uint32( &(msg->xid), vc_filesys_client.cur_xid );
//fill in cmd id VC_FILESYS_OPEN etc
vchi_writebuf_uint32( &(msg->cmd_code), cmd_id );
//we always have cmd_id, xid
msg_len += 8;
//return response code
return (int) vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
}
static int vc_send_response( FILESERV_MSG_T* msg, uint32_t retval, uint32_t nbytes )
{
int success = -1;
//convert all to over the wire values
vchi_writebuf_uint32(&msg->cmd_code, retval);
vchi_writebuf_uint32(&msg->xid, msg->xid);
vchi_writebuf_uint32(&msg->params[0], msg->params[0]);
vchi_writebuf_uint32(&msg->params[1], msg->params[1]);
vchi_writebuf_uint32(&msg->params[2], msg->params[2]);
vchi_writebuf_uint32(&msg->params[3], msg->params[3]);
//start with 8 because always xid and retval
nbytes += 8;
if(vcos_verify(nbytes <= VCHI_MAX_MSG_SIZE))
success = (int) vchi_msg_queue( vc_filesys_client.open_handle, msg, nbytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
return success;
}
/******************************************************************************
NAME
vc_fs_message_handler
SYNOPSIS
static int vc_fs_message_handler()
FUNCTION
Handle messages from the co-processor.
RETURNS
0 - No message found.
1 - Request received and actioned.
2 - Reply received.
******************************************************************************/
static int vc_fs_message_handler( FILESERV_MSG_T* msg, uint32_t nbytes )
{
int rr = 0;
uint32_t xid = vchi_readbuf_uint32(&msg->xid);
if (xid == vc_filesys_client.cur_xid) {
//memcpy reply to msg should really peek before
vc_filesys_client.fileserv_msg.xid = xid;
vc_filesys_client.fileserv_msg.cmd_code = vchi_readbuf_uint32(&msg->cmd_code);
vc_filesys_client.fileserv_msg.params[0] = vchi_readbuf_uint32(&msg->params[0]);
vc_filesys_client.fileserv_msg.params[1] = vchi_readbuf_uint32(&msg->params[1]);
vc_filesys_client.fileserv_msg.params[2] = vchi_readbuf_uint32(&msg->params[2]);
vc_filesys_client.fileserv_msg.params[3] = vchi_readbuf_uint32(&msg->params[3]);
//copy any data, 24 is size of header
if(nbytes >24)
memcpy(&vc_filesys_client.fileserv_msg.data, msg->data, (nbytes-24));
vc_filesys_client.resp_code = (int32_t)vc_filesys_client.fileserv_msg.cmd_code;
if (vc_filesys_client.resp_code == FILESERV_RESP_ERROR) {
vc_filesys_client.err_no = (int32_t)vc_filesys_client.fileserv_msg.params[0];
}
// signal vchi_msg_stub which will be waiting for response
vcos_event_signal(&vc_filesys_client.response_event);
rr = 2;
}
else if ((xid & 0x80000000UL) == 0x80000000UL) {
/* Process new requests from the co-processor */
uint32_t retval = FILESERV_RESP_OK;
//this is the number of uint32_t param[] + data that we send back to VC in bytes
uint32_t rlen = 0;
int i;
switch (msg->cmd_code) {
case VC_FILESYS_CLOSE:
i = vc_hostfs_close((int)msg->params[0]);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_CLOSEDIR:
i = vc_hostfs_closedir((void *)msg->params[0]);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_FORMAT:
i = vc_hostfs_format((const char *)msg->data);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_FREESPACE:
i = vc_hostfs_freespace((const char *)msg->data);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t)i;
rlen = 4;
}
break;
case VC_FILESYS_FREESPACE64:
{
int64_t freespace;
freespace = vc_hostfs_freespace64((const char *)msg->data);
if (freespace < (int64_t)0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t)freespace;
msg->params[1] = (uint32_t)(freespace>>32);
rlen = 8;
}
}
break;
case VC_FILESYS_GET_ATTR:
{
fattributes_t attr;
i = vc_hostfs_get_attr((const char *)msg->data,
&attr);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t) attr;
rlen = 4;
}
}
break;
case VC_FILESYS_LSEEK:
i = vc_hostfs_lseek( (int)msg->params[0],
(int)msg->params[1],
(int)msg->params[2]);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t) i;
rlen = 4;
}
break;
case VC_FILESYS_LSEEK64:
{
int64_t offset;
offset = (((int64_t) msg->params[2]) << 32) + msg->params[1];
offset = vc_hostfs_lseek64( (int)msg->params[0], offset, (int)msg->params[3]);
if (offset < (int64_t)0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t)offset;
msg->params[1] = (uint32_t)(offset>>32);
rlen = 8;
}
}
break;
case VC_FILESYS_MKDIR:
i = vc_hostfs_mkdir((const char *)msg->data);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_OPEN:
i = vc_hostfs_open((const char *)msg->data,
(int) msg->params[0]);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
} else {
msg->params[0] = (uint32_t) i;
}
rlen = 4;
break;
case VC_FILESYS_OPENDIR:
msg->params[0] = (uint32_t)vc_hostfs_opendir(
(const char *)msg->data);
if ((void *)msg->params[0] == NULL) {
retval = FILESERV_RESP_ERROR;
}
rlen = 4;
break;
case VC_FILESYS_READ:
{
uint32_t fd = msg->params[0];
uint32_t offset = msg->params[1];
int total_bytes = (int)msg->params[2];
uint32_t nalign_bytes = msg->params[3];
i = 0;
if(!vcos_verify(((int)vc_filesys_client.bulk_buffer & (VCHI_BULK_ALIGN-1)) == 0 &&
total_bytes <= FILESERV_MAX_BULK))
{
retval = FILESERV_RESP_ERROR;
rlen = 4;
break;
}
rlen = 0;
//perform any seeking
if ( (uint32_t)0xffffffffUL != offset)
{
i = vc_hostfs_lseek( (int)fd,
(long int) offset,
VC_FILESYS_SEEK_SET);
if ( 0 > i)
{
retval = FILESERV_RESP_ERROR;
rlen = 4;
break;
}
}
//put it all in one msg
if(total_bytes <= FILESERV_MAX_DATA) {
i = vc_hostfs_read( (int)fd,
msg->data,
(unsigned int) total_bytes);
if(i < 0) {
retval = FILESERV_RESP_ERROR;
msg->params[0] = 0;
}
else {
retval = FILESERV_RESP_OK;
//send back length of read
msg->params[0] = (uint32_t) i;
}
msg->params[1] = 0;
rlen = 16 + (uint32_t) i;
}
//bulk transfer required
else {
uint32_t end_bytes = 0;
retval = FILESERV_BULK_WRITE;
//we send the bytes required for HOST buffer align
if(nalign_bytes) {
i = vc_hostfs_read( (int)fd,
msg->data,
(unsigned int)nalign_bytes);
if(i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 16;
break;
}
else if(i != (int)nalign_bytes) {
//all data will be in one msg
retval = FILESERV_RESP_OK;
msg->params[0] = (uint32_t) i;
msg->params[1] = 0;
rlen = 16 + (uint32_t) i;
//send response
break;
}
total_bytes -= i;
rlen += (uint32_t) i;
}
//bulk bytes
i = vc_hostfs_read((int)fd, vc_filesys_client.bulk_buffer, (unsigned int)total_bytes);
if(i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 16;
break;
}
else if((i+nalign_bytes) <= FILESERV_MAX_DATA) {
retval = FILESERV_RESP_OK;
memcpy(&msg->data[nalign_bytes], &vc_filesys_client.bulk_buffer[0], (size_t) i);
//read size
msg->params[0] = (i + nalign_bytes);
msg->params[1] = 0;
rlen = i + nalign_bytes + 16;
break;
}
//copy end unaligned length bytes into msg->data
end_bytes = (uint32_t) (i & (VCHI_BULK_GRANULARITY-1));
if(end_bytes) {
int end_index = i - (int) end_bytes;
memcpy(&msg->data[nalign_bytes], &vc_filesys_client.bulk_buffer[end_index], end_bytes);
rlen += end_bytes;
}
//send back total bytes
msg->params[0] = (uint32_t)(i + nalign_bytes);
//number of end bytes
msg->params[1] = end_bytes;
//number of bulk bytes
msg->params[2] = (uint32_t)(i - end_bytes);
//16 for param len
rlen += 16;
//queue bulk to be sent
if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle,
vc_filesys_client.bulk_buffer,
msg->params[2],
VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
NULL ) != 0)
{
retval = FILESERV_RESP_ERROR;
rlen = 4;
break;
}
}
}
//send response
break;
case VC_FILESYS_READDIR:
{
struct dirent result;
if (vc_hostfs_readdir_r((void *)msg->params[0],
&result) == NULL) {
retval = FILESERV_RESP_ERROR;
rlen = 4;
} else {
rlen = (uint32_t) (16+fs_host_direntbytestream_create(&result,
(void *)msg->data));
}
}
break;
case VC_FILESYS_REMOVE:
i = vc_hostfs_remove((const char *)msg->data);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_RENAME:
i = (int) strlen((char *)msg->data);
if (vc_hostfs_rename((const char *)msg->data,
(const char *)&msg->data[i+1])
!= 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_SETEND:
i = vc_hostfs_setend( (int)msg->params[0] );
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_SET_ATTR:
i = vc_hostfs_set_attr((const char *)msg->data,
(fattributes_t)msg->params[0]);
if (i != 0) {
retval = FILESERV_RESP_ERROR;
}
rlen = 0;
break;
case VC_FILESYS_TOTALSPACE:
i = vc_hostfs_totalspace((const char *)msg->data);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t) i;
rlen = 4;
}
break;
case VC_FILESYS_TOTALSPACE64:
{
int64_t totalspace;
totalspace = vc_hostfs_totalspace64((const char *)msg->data);
if (totalspace < (int64_t)0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t)totalspace;
msg->params[1] = (uint32_t)(totalspace>>32);
rlen = 8;
}
}
break;
#if 0 // I don't think host systems are ready for these yet
case VC_FILESYS_SCANDISK:
vc_hostfs_scandisk((const char *)msg->data);
rlen = 0;
break;
case VC_FILESYS_CHKDSK:
i = vc_hostfs_chkdsk((const char *)msg->data, msg->params[0]);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
rlen = 0;
} else {
msg->params[0] = (uint32_t)i;
rlen = 4;
}
break;
#endif
case VC_FILESYS_WRITE:
{
uint32_t fd = msg->params[0];
// uint32_t offset = msg->params[1];
int total_bytes = (int)msg->params[2];
uint32_t nalign_bytes = msg->params[3];
retval = FILESERV_RESP_OK;
i = 0;
//everything in one msg
if(total_bytes <= FILESERV_MAX_DATA)
{
i = vc_hostfs_write( (int)fd,
msg->data,
(unsigned int) total_bytes);
if (i < 0) {
retval = FILESERV_RESP_ERROR;
} else {
msg->params[0] = (uint32_t) i;
}
rlen = 4;
//send response
break;
}
else
{
uint32_t end_bytes;
uint32_t bulk_bytes;
uint32_t total_bytes_written = 0;
i = 0;
//one return param
rlen = 4;
retval = FILESERV_BULK_READ;
//write bytes required for VC buffer align
if(nalign_bytes) {
i = vc_hostfs_write( (int)fd,
msg->data,
(unsigned int)nalign_bytes);
if(i < 0) {
retval = FILESERV_RESP_ERROR;
msg->params[0] = 0;
//break from switch and send reply
break;
}
total_bytes_written += i;
total_bytes -= nalign_bytes;
}
//calculate bytes that wil lbe sent by bulk
bulk_bytes = (uint32_t)((total_bytes)&(~(VCHI_BULK_ALIGN-1)));
end_bytes = total_bytes-bulk_bytes;
if(vchi_bulk_queue_receive(vc_filesys_client.open_handle,
vc_filesys_client.bulk_buffer,
bulk_bytes,
VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
NULL) != 0 ||
(i = vc_hostfs_write( (int)fd,
vc_filesys_client.bulk_buffer,
(unsigned int) bulk_bytes)) < 0)
{
retval = FILESERV_RESP_ERROR;
msg->params[0] = 0;
break;
}
total_bytes_written += i;
if(end_bytes) {
i = vc_hostfs_write( (int)fd,
msg->data+nalign_bytes,
(unsigned int)end_bytes);
total_bytes_written += i;
}
if(i < 0) {
retval = FILESERV_RESP_ERROR;
msg->params[0] = 0;
break;
}
msg->params[0] = total_bytes_written;
}
}
break;
default:
rlen = 4;
retval = FILESERV_RESP_ERROR;
break;
}
//convert all to over the wire values and send
vc_send_response( msg, retval, rlen );
rr = 1;
} else {
/* A message has been left in the fifo and the host side has been reset.
The message needs to be flushed. It would be better to do this by resetting
the fifos. */
}
return rr;
}
/******************************************************************************
NAME
showmsg
SYNOPSIS
static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
struct file_service_msg_body const * body)
FUNCTION
De-bug tool: prints out fifo message.
RETURNS
void
******************************************************************************/
#ifdef PRINTF
static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
struct file_service_msg_body const * body)
{
unsigned int ael = (head->ext_length + 15) & ~15;
printf("Sync=%08x XID=%08x Code=%08x Extlen=%08x (%d bytes follow)\n",
head->sync, head->xid, head->cmd_code, head->ext_length, ael);
if (ael) {
unsigned int i;
printf("Content:");
for (i = 0; i < 4 && i*4 < head->ext_length; ++i) printf(" %08x", body->params[i]);
//for(i = 0; i+16 < head->ext_length; ++i) printf(" %02x", body->data[i]);
if (head->ext_length > 16) printf(" plus %d bytes\n", head->ext_length);
}
printf("\n");
}
#endif
/******************************************************************************
NAME
fs_host_direntbytestream_create
SYNOPSIS
static int fs_host_direntbytestream_create(struct dirent *d, void *buffer)
FUNCTION
Turns a variable of type struct dirent into a compiler independent byte
stream, which is stored in buffer.
RETURNS
Successful completion: The length of the byte stream
Otherwise: -1
******************************************************************************/
static void write_bytestream(void *a, char *b, int n)
{
int i;
for (i=0;i<n;i++) {
b[i] = ((char *)a)[i];
}
for (;i<4;i++) {
b[i] = 0;
}
}
static int fs_host_direntbytestream_create(struct dirent *d, void *buffer)
{
char *buf = (char*)buffer;
// Write d_name (D_NAME_MAX_SIZE chars)
memcpy(buf, &d->d_name, D_NAME_MAX_SIZE);
buf += D_NAME_MAX_SIZE;
// Write d_size (unsigned int)
write_bytestream((void *)&d->d_size, buf, (int)sizeof(d->d_size));
buf += 4;
// Write d_attrib (int)
write_bytestream((void *)&d->d_attrib, buf, (int)sizeof(d->d_attrib));
buf += 4;
// Write d_modtime (time_t)
write_bytestream((void *)&d->d_modtime, buf, (int)sizeof(d->d_modtime));
buf += 4;
return (int)(buf-(char *)buffer);
}
/******************************************************************************
NAME
fs_host_direntbytestream_interp
SYNOPSIS
static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer)
FUNCTION
Turns a compiler independent byte stream back into a struct of type dirent.
RETURNS
Successful completion: 0
Otherwise: -1
******************************************************************************/
static void read_bytestream(void *a, char *b, int n)
{
int i;
for (i=0;i<n;i++) {
((char *)a)[i] = b[i];
}
}
static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer)
{
char *buf = (char*)buffer;
// Read d_name (D_NAME_MAX_SIZE chars)
memcpy(&d->d_name, buf, D_NAME_MAX_SIZE);
buf += D_NAME_MAX_SIZE;
// Read d_size (unsigned int)
read_bytestream((void *)&d->d_size, buf, (int)sizeof(d->d_size));
d->d_size = VC_VTOH32(d->d_size);
buf += 4;
// Read d_attrib (int)
read_bytestream((void *)&d->d_attrib, buf, (int)sizeof(d->d_attrib));
d->d_attrib = VC_VTOH32(d->d_attrib);
buf += 4;
// Read d_modtime (time_t)
read_bytestream((void *)&d->d_modtime, buf, (int)sizeof(d->d_modtime));
d->d_modtime = VC_VTOH32(d->d_modtime);
return;
}
void vc_filesys_sendreset(void)
{
//TODO
}