/* * dev_fbf.c - FBF (Block Device Controler) generic device API implementation. * * Author Alain Greiner (2016) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MK * * ALMOS-MKH.is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH.is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-kernel; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////////////// // Extern global variables ///////////////////////////////////////////////////////////////////////////////////////// extern chdev_directory_t chdev_dir; // allocated in kernel_init.c //////////////////////////////////// void dev_fbf_init( chdev_t * chdev ) { // set FBF chdev extension fields // TODO this should be done in the impementation // TODO specific part, as these parameters must be obtained from the hardware. chdev->ext.fbf.width = CONFIG_FBF_WIDTH; chdev->ext.fbf.height = CONFIG_FBF_HEIGHT; // get implementation uint32_t impl = chdev->impl; // set chdev name strcpy( chdev->name, "fbf" ); // call driver init function if( impl == IMPL_FBF_SCL ) { // TODO } else { assert( false , __FUNCTION__ , "undefined FBF device implementation" ); } } // end dev_fbf_init() ///////////////////////////////////////// void dev_fbf_get_size( uint32_t * width, uint32_t * height ) { // get extended pointer on FBF chdev descriptor xptr_t dev_xp = chdev_dir.fbf[0]; assert( (dev_xp != XPTR_NULL) , __FUNCTION__ , "undefined FBF chdev descriptor" ); // get FBF chdev cluster and local pointer cxy_t dev_cxy = GET_CXY( dev_xp ); chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp ); // return values *width = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->ext.fbf.width ) ); *height = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->ext.fbf.height ) ); } // end dev_fbf_get_size() /////////////////////// error_t dev_fbf_alloc() { // get extended pointer on FBF chdev descriptor xptr_t dev_xp = chdev_dir.fbf[0]; assert( (dev_xp != XPTR_NULL) , __FUNCTION__ , "undefined FBF chdev descriptor" ); // get FBF chdev cluster and local pointer cxy_t dev_cxy = GET_CXY( dev_xp ); chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp ); // try to get FBF ownership return remote_spinlock_trylock( XPTR( dev_cxy , &dev_ptr->wait_lock ) ); } // end dev_fbf_alloc() /////////////////// void dev_fbf_free() { // get extended pointer on FBF chdev descriptor xptr_t dev_xp = chdev_dir.fbf[0]; assert( (dev_xp != XPTR_NULL) , __FUNCTION__ , "undefined FBF chdev descriptor" ); // get FBF chdev cluster and local pointer cxy_t dev_cxy = GET_CXY( dev_xp ); chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp ); // release FBF ownership remote_spinlock_unlock( XPTR( dev_cxy , &dev_ptr->wait_lock ) ); } // end dev_fbf_free() ////////////////////////////////////////////////////////////////////////////////// // This static function is called by dev_fbf_read() & dev_fbf_write() functions. // It builds and registers the command in the calling thread descriptor, after // translation of buffer virtual address to physical address. // Then, it registers the calling thead in the relevant DMA chdev waiting queue. // Finally it blocks on the THREAD_BLOCKED_DEV condition and deschedule. ////////////////////////////////////i///////////////////////////////////////////// static error_t dev_fbf_access( bool_t to_fbf, char * buffer, uint32_t length, uint32_t offset ) { error_t error; paddr_t buf_paddr; thread_t * this = CURRENT_THREAD; // pointer on client thread // Get buffer physical address error = vmm_v2p_translate( CONFIG_KERNEL_IDENTITY_MAP , buffer , &buf_paddr ); if( error ) { printk("\n[ERROR] in %s : cannot translate vaddr = %p in process %x\n", __FUNCTION__ , buffer , this->process->pid ); return EINVAL; } fbf_dmsg("\n[INFO] %s : thread %x in process %x / vaddr = %p / paddr = %l\n", __FUNCTION__ , this->trdid , this->process->pid , buffer , buf_paddr ); // get extended pointer on FBF chdev descriptor xptr_t fbf_xp = chdev_dir.fbf[0]; assert( (fbf_xp != XPTR_NULL) , __FUNCTION__ , "undefined FBF chdev descriptor" ); // get FBF chdev cluster and local pointer cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = (chdev_t *)GET_PTR( fbf_xp ); // get frame buffer base address, width and height xptr_t base = hal_remote_lwd( XPTR( fbf_cxy , &fbf_ptr->base ) ); uint32_t width = hal_remote_lw ( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) ); uint32_t height = hal_remote_lw ( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) ); // check offset and length versus FBF size if( (offset + length) > (width * height) ) { printk("\n[ERROR] in %s : offset = %d / length = %d / width = %d / height = %d\n", __FUNCTION__ , offset , length , width , height ); return EINVAL; } // compute extended pointers on frame buffer and memory buffer xptr_t mem_buf_xp = XPTR( local_cxy , (void *)(intptr_t)buf_paddr ); xptr_t fbf_buf_xp = base + offset; // register command in DMA chdev if( to_fbf ) dev_dma_remote_memcpy( fbf_buf_xp , mem_buf_xp , length ); else dev_dma_remote_memcpy( mem_buf_xp , fbf_buf_xp , length ); return 0; } // end dev_fbf_access() //////////////////////////////////////////// error_t dev_fbf_read( char * buffer, uint32_t length, uint32_t offset ) { return dev_fbf_access( false , buffer , length , offset ); } //////////////////////////////////////////// error_t dev_fbf_write( char * buffer, uint32_t length, uint32_t offset ) { return dev_fbf_access( true , buffer , length , offset ); }