/* 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 #include #include #include #include #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;id_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;id_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 }