/* * dev_fbf.c - FBF (Frame Buffer) generic device API implementation. * * Author Alain Greiner (2016,2017,2018,2019,2020) * * 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 #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////////////// // Extern global variables ///////////////////////////////////////////////////////////////////////////////////////// extern chdev_directory_t chdev_dir; // allocated in kernel_init.c /////////////////////////////////////////// char * dev_fbf_cmd_str( uint32_t cmd_type ) { if ( cmd_type == FBF_GET_CONFIG ) return "GET_CONFIG"; else if( cmd_type == FBF_CREATE_WINDOW ) return "CREATE_WINDOW"; else if( cmd_type == FBF_ACTIVE_WINDOW ) return "ACTIVE_WINDOW"; else if( cmd_type == FBF_DELETE_WINDOW ) return "DELETE_WINDOW"; else if( cmd_type == FBF_MOVE_WINDOW ) return "MOVE_WINDOW"; else if( cmd_type == FBF_REFRESH_WINDOW ) return "REFRESH_WINDOW"; else if( cmd_type == FBF_FRONT_WINDOW ) return "FRONT_WINDOW"; else if( cmd_type == FBF_RESIZE_WINDOW ) return "RESIZE_WINDOW"; else if( cmd_type == FBF_DIRECT_WRITE ) return "DIRECT_WRITE"; else if( cmd_type == FBF_DIRECT_READ ) return "DIRECT_READ"; else return "undefined"; } //////////////////////////////////////////////// xptr_t dev_fbf_get_xptr_from_wid( uint32_t wid ) { thread_t * this = CURRENT_THREAD; pid_t pid = this->process->pid; trdid_t trdid = this->trdid; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointer on windows_tbl[wid] xptr_t entry_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] ); // get pointers on searched window xptr_t window_xp = hal_remote_l64( entry_xp ); cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); if( window_xp == XPTR_NULL ) { printk("\n[ERROR] in %s / client thread[%x,%x] request a non registered wid (%d)\n", __FUNCTION__, pid, trdid, wid ); return XPTR_NULL; } // get owner process PID from window descriptor pid_t owner_pid = hal_remote_l32( XPTR( window_cxy , &window_ptr->pid ) ); if( pid != owner_pid ) { printk("\n[ERROR] in %s / client thread[%x,%x] not owner of wid (%d) / owner is (%x)\n", __FUNCTION__, pid, trdid, owner_pid, wid ); return XPTR_NULL; } return window_xp; } // end dev_fbf_get_xptr_from_wid() //////////////////////////////////// void dev_fbf_init( chdev_t * fbf ) { uint32_t wid; // set chdev name strcpy( fbf->name, "fbf" ); // initialize lock protecting the windows remote_rwlock_init( XPTR( local_cxy , &fbf->ext.fbf.windows_lock ), LOCK_FBF_WINDOWS ); // initialize root of windows xlist xlist_root_init( XPTR( local_cxy , &fbf->ext.fbf.windows_root ) ); // initialize windows_tbl[] array for( wid = 0 ; wid < CONFIG_FBF_WINDOWS_MAX_NR ; wid++ ) { fbf->ext.fbf.windows_tbl[wid] = XPTR_NULL; } // initialize wid allocator bitmap bitmap_init( fbf->ext.fbf.windows_bitmap , CONFIG_FBF_WINDOWS_MAX_NR ); // call driver init function to initialize the harware FBF // and initialize the width, height, and subsampling FBF chdev fields hal_drivers_fbf_init( fbf ); } // end dev_fbf_init() ////////////////////////////////////////// void dev_fbf_get_config( uint32_t * width, uint32_t * height, uint32_t * type ) { // get extended pointer on FBF chdev descriptor xptr_t dev_xp = chdev_dir.fbf[0]; assert( __FUNCTION__, (dev_xp != XPTR_NULL) , "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_l32( XPTR( dev_cxy , &dev_ptr->ext.fbf.width ) ); *height = hal_remote_l32( XPTR( dev_cxy , &dev_ptr->ext.fbf.height ) ); *type = hal_remote_l32( XPTR( dev_cxy , &dev_ptr->ext.fbf.subsampling ) ); } // end dev_fbf_get_config() ///////////////////////////////////////////////// uint32_t dev_fbf_create_window( uint32_t nlines, uint32_t npixels, uint32_t l_min, uint32_t p_min, intptr_t * user_buffer ) { fbf_window_t * window; // window descriptor (created in local cluster) vseg_t * vseg; // vseg descriptor (created in reference cluster) intptr_t vseg_base; // vseg base address in user space // get local pointers on calling thread and process thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if DEBUG_DEV_FBF uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enter : nlines %d / npixels %d / l_min %d / p_min %d / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, nlines, npixels, l_min, p_min, cycle ); #endif // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // check fbf_xp definition assert( __FUNCTION__, (fbf_xp != XPTR_NULL) , "undefined FBF chdev descriptor" ); // get FBF width and height uint32_t fbf_width = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) ); uint32_t fbf_height = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) ); // check new window size and coordinates if( (((l_min + nlines) > fbf_height) || ((p_min + npixels) > fbf_width)) ) { printk("\n[ERROR] in %s / thread[%x,%x]" "illegal new coordinates (%d,%d) for window (%d,%d) in fbf (%d,%d)\n", process->pid, this->trdid, p_min, l_min, npixels, nlines, fbf_width, fbf_height ); return -1; } // build extended pointers on windows lock, root, and wid allocator xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); xptr_t windows_bitmap_xp = XPTR( fbf_cxy , fbf_ptr->ext.fbf.windows_bitmap ); // allocate memory for the window descriptor in local cluster window = kmem_alloc( bits_log2(sizeof(fbf_window_t)) , AF_ZERO ); if( window == NULL ) { printk("\n[ERROR] in %s / thread[%x,%x] cannot allocate window descriptor\n", __FUNCTION__, process->pid, this->trdid ); return -1; } #if (DEBUG_DEV_FBF & 1) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] created window descriptor %x / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, window, cycle ); #endif // getpointers on reference process xptr_t ref_xp = process->ref_xp; process_t * ref_ptr = GET_PTR( ref_xp ); cxy_t ref_cxy = GET_CXY( ref_xp ); // allocate a new vseg, and introduce it in the reference process VSL if( ref_cxy == local_cxy ) { vseg = vmm_create_vseg( process, // owner process VSEG_TYPE_ANON, // localised, public 0, // base, unused for ANON nlines * npixels, // size 0, // file_offset, unused for ANON 0, // file_size, unused for ANON XPTR_NULL, // mapper_xp, unused for ANON local_cxy ); // mapping cluster } else { rpc_vmm_create_vseg_client( ref_cxy, ref_ptr, VSEG_TYPE_ANON, 0, // base, unused for ANON nlines * npixels, // size 0, // file_offset, unused for ANON 0, // file size, unused for ANON XPTR_NULL, // mapper_xp, unused for ANON local_cxy, &vseg ); } if( vseg == NULL ) { printk("\n[ERROR] in %s / thread[%x,%x] cannot create vseg in reference cluster\n", __FUNCTION__, process->pid, this->trdid ); kmem_free( window , bits_log2(sizeof(fbf_window_t)) ); return -1; } // get vseg base vseg_base = (intptr_t)hal_remote_lpt( XPTR( ref_cxy , &vseg->min ) ); #if (DEBUG_DEV_FBF & 1) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] allocated vseg / base %x / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, vseg_base, cycle ); #endif // take the lock protecting windows in write mode remote_rwlock_wr_acquire( windows_lock_xp ); // allocate a wid from allocator in FBF descriptor extension uint32_t wid = bitmap_remote_alloc( windows_bitmap_xp , CONFIG_FBF_WINDOWS_MAX_NR ); if( wid == 0xFFFFFFFF ) { printk("\n[ERROR] in %s / thread[%x,%x] cannot allocate buffer for window\n", __FUNCTION__, process->pid, this->trdid ); kmem_free( window , bits_log2(sizeof(fbf_window_t)) ); vmm_remove_vseg( process , vseg ); return -1; } // initialize window descriptor window->pid = process->pid; window->wid = wid; window->height = nlines; window->width = npixels; window->l_min = l_min; window->p_min = p_min; window->hidden = true; window->buffer = (uint8_t *)vseg_base; // register new window in xlist rooted in FBF extension xlist_add_last( windows_root_xp , XPTR( local_cxy , &window->xlist ) ); // build extended pointer on relevant entry in windows_tbl[] array xptr_t windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] ); // register new window in windows_tbl[] stored in FBF extension hal_remote_s64( windows_tbl_xp , XPTR( local_cxy , window ) ); // release the lock protecting windows in write mode remote_rwlock_wr_release( windows_lock_xp ); #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / wid %d / buffer %x / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid , window->buffer, cycle ); #endif // return pointer on allocated buffer *user_buffer = vseg_base; return wid; } // end dev_fbf_create_window() ///////////////////////////////////////////// error_t dev_fbf_active_window( uint32_t wid, uint32_t active ) { #if DEBUG_DEV_FBF thread_t * thi = CURRENT_THREAD; uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters : wid %d / active %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid, active, cycle ); #endif // get extended pointer on window to be activated xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and local pointer on target window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // set/reset hidden flag in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , (active == 0) ? 1 : 0 ); #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif return 0; } // end dev_fbf_active_window() //////////////////////////////////////////////////////////////////////////////////////// // This static function is called by dev_fbf_refresh_window(), dev_fbf_move_window(), // dev_fbf_front_window(), dev_fbf_delete_window(), and dev_fbf_resize_window(). // It updates all lines of a pseudo window identified by the , , , // and arguments, that are dynamically computed by the caller. // This function scan all registered windows to take into account the overlap priorities // defined by the FBF xlist of windows. It takes the lock protecting xlist in read mode. //////////////////////////////////////////////////////////////////////////////////////// // Implementation Note: // This function contains two loops. // - the external loop builds one line of the pseudo window per iteraiion in a local // line_buffer. One line contains [p_max - p_min] pixels. Then, it calls the FBF // driver (one driver call per line) to write this line into the Frame Buffer. // - the internal loop scan the list of the registered windows in increasing priority, // and for each registered window that has a non empty intersection with the handled // line, it updates the line_buffer, using the hal_copy_from_uspace() function // to get the most up-to-date user-defined data. //////////////////////////////////////////////////////////////////////////////////////// // @ p_min : [in] upper left corner X coordinate in FBF reference // @ p_max : [in] upper left corner Y coordinate in FBF reference. // @ l_min : [in] lower right corner X coordinate in FBF reference (excluded). // @ l_max : [in] lower right corner Y coordinate in FBF reference (excluded). //////////////////////////////////////////////////////////////////////////////////////// error_t fbf_update( uint32_t p_min, uint32_t l_min, uint32_t p_max, uint32_t l_max ) { uint32_t line; // iterator to scan the FBF lines uint32_t pixel; // iterator to scan pixels in one FBF line xptr_t iter_xp; // iterator to scan the list of windows error_t error; // this intermediate buffer to build one pseudo-window line uint8_t line_buffer[CONFIG_FBF_WINDOWS_MAX_WIDTH]; // get pointer on calling thread and core lid thread_t * this = CURRENT_THREAD; #if DEBUG_DEV_FBF uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] enter : p_min %d / l_min %d / p_max %d / l_max %d / cycle %d\n", __FUNCTION__, p_min, l_min, p_max, l_max, cycle ); #endif // get pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // get frame buffer width and height uint32_t fbf_width = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) ); uint32_t fbf_height = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) ); // check arguments assert( __FUNCTION__, (p_min < fbf_width) && (p_max <= fbf_width) && (l_min < fbf_height) && (l_max <= fbf_height) , "illegal arguments" ); // get pointer on driver command function dev_cmd_t * cmd = hal_remote_lpt( XPTR( fbf_cxy , &fbf_ptr->cmd ) ); // build extended pointers on windows xlist root and lock xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); error = 0; // 1. external loop on pseudo window lines (in FBF reference) for( line = l_min ; line < l_max ; line++ ) { // reset the line buffer to default value for( pixel = 0 ; pixel < (p_max - p_min) ; pixel++ ) line_buffer[pixel] = 127; // take the lock in read mode remote_rwlock_rd_acquire( windows_lock_xp ); // 2. internal loop on all registered windows XLIST_FOREACH( windows_root_xp , iter_xp ) { // get pointers on current target window xptr_t tgt_xp = XLIST_ELEMENT( iter_xp , fbf_window_t , xlist ); fbf_window_t * tgt_ptr = GET_PTR( tgt_xp ); cxy_t tgt_cxy = GET_CXY( tgt_xp ); // get target window min and max coordinates in FBF reference bool_t hidden = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->hidden ) ); uint32_t w_l_min = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->l_min ) ); uint32_t w_p_min = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->p_min ) ); uint32_t w_height = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->height ) ); uint32_t w_width = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->width ) ); uint32_t w_l_max = w_l_min + w_height; uint32_t w_p_max = w_p_min + w_width; // does nothing when target window is hidden // or the pseudo window line does not overlap the target window if( (hidden == true) || (line < w_l_min) || (line >= w_l_max) || (p_max < w_p_min) || (p_min >= w_p_max) ) continue; // get pointer on buffer associated to target window in user space uint8_t * w_buffer = hal_remote_lpt( XPTR( tgt_cxy , &tgt_ptr->buffer ) ); // get min & max indexes for pixels to be moved in FBF reference uint32_t f_pixel_min = (p_min < w_p_min) ? w_p_min : p_min; uint32_t f_pixel_max = (p_max < w_p_max) ? p_max : w_p_max; // compute number of pixels to move from w_buffer to f_buffer uint32_t npixels = f_pixel_max - f_pixel_min; // compute offset in line_buffer uint32_t line_offset = f_pixel_min - p_min; // compute line index in window uint32_t w_line = line - w_l_min; // compute offset in window buffer uint32_t w_offset = (w_line * w_height) + f_pixel_min - w_p_min; // move pixels from w_buffer (user space) to line_buffer (kernel space) hal_copy_from_uspace( XPTR( local_cxy , &line_buffer[line_offset] ), &w_buffer[w_offset], npixels ); } // end for windows // release the lock remote_rwlock_rd_release( windows_lock_xp ); // compute offset in FBF uint32_t fbf_offset = p_min + (line * fbf_width); // register command in calling thread descriptor this->fbf_cmd.dev_xp = fbf_xp; this->fbf_cmd.type = FBF_DRIVER_KERNEL_WRITE; this->fbf_cmd.buffer = line_buffer; this->fbf_cmd.npixels = p_max - p_min; this->fbf_cmd.offset = fbf_offset; // call driver to display one line cmd( XPTR( local_cxy , this ) ); error |= this->fbf_cmd.error; } // end for lines #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] exit / cycle %d\n", __FUNCTION__, cycle ); #endif // return I/O operation status return error; } // end fbf_update() ////////////////////////////////////////////// error_t dev_fbf_delete_window( uint32_t wid ) { thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if DEBUG_DEV_FBF uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters : wid %d / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, wid, cycle ); #endif // get extended pointer on window to be deleted xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointers on windows lock, windows_tbl[wid] and wid allocator xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t wid_bitmap_xp = XPTR( fbf_cxy , fbf_ptr->ext.fbf.windows_bitmap ); xptr_t windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] ); // get cluster and local pointer on window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // get relevant info from window descriptor uint32_t p_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) ); uint32_t l_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) ); uint32_t npixels = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) ); uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) ); uint8_t * buffer = hal_remote_lpt( XPTR( window_cxy , &window_ptr->buffer ) ); // 1. set the hidden bit in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , true ); // 2. refresh the window in FBF fbf_update( p_min, l_min, p_min + npixels, l_min + nlines ); // 3. take the lock protecting windows in write mode remote_rwlock_wr_acquire( windows_lock_xp ); // 4. remove the window from windows_tbl[] array hal_remote_s64( windows_tbl_xp , XPTR_NULL ); // 5. remove the window from xlist xlist_unlink( XPTR( window_cxy , &window_ptr->xlist ) ); // 6. release wid to bitmap bitmap_remote_clear( wid_bitmap_xp , wid ); // 7. release the lock protecting windows in write mode remote_rwlock_wr_release( windows_lock_xp ); // 8. release memory allocated for window descriptor kmem_remote_free( window_cxy , window_ptr , bits_log2(sizeof(fbf_window_t)) ); // 9. release the associated vseg vmm_global_delete_vseg( process , (intptr_t)buffer ); #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, cycle ); #endif return 0; } // end dev_fbf_delete_window() //////////////////////////////////////////// error_t dev_fbf_move_window( uint32_t wid, uint32_t l_new, uint32_t p_new ) { #if DEBUG_DEV_FBF thread_t * this = CURRENT_THREAD; uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters : wid %d / l_new %d / p_new %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid, l_new, p_new, cycle ); #endif // get extended pointer on window to be moved xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointers on windows lock and root xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); // get cluster and local pointer on target window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // get target window coordinates, width and height uint32_t p_old = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) ); uint32_t l_old = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) ); uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) ); uint32_t npixels = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) ); // build extended pointer on window xlist_entry xptr_t xlist_entry_xp = XPTR( window_cxy , &window_ptr->xlist ); // does nothing if no change if( (p_new == p_old) && (l_new == l_old) ) return 0; // 1. set the "hidden" flag in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , true ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] hidden set\n", __FUNCTION__ ); #endif // 2. update the FBF for the old window position fbf_update( p_old , l_old , p_old + npixels, l_old + nlines ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] refreshed old window\n", __FUNCTION__ ); #endif // 3. take the lock protecting windows in write mode remote_rwlock_wr_acquire( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock taken\n", __FUNCTION__ ); #endif // 4. set the new coordinates in the window descriptor, hal_remote_s32( XPTR( window_cxy , &window_ptr->l_min ), l_new ); hal_remote_s32( XPTR( window_cxy , &window_ptr->p_min ), p_new ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] l_min & p_min updated\n", __FUNCTION__ ); #endif // 5. gives the window the highest priority xlist_unlink( xlist_entry_xp ); xlist_add_last( windows_root_xp , xlist_entry_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] set high priority\n", __FUNCTION__ ); #endif // 6. release the lock protecting windows in write mode remote_rwlock_wr_release( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock released\n", __FUNCTION__ ); #endif // 7. reset the "hidden" flag in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , false ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] hidden reset\n", __FUNCTION__ ); #endif // 8. update the FBF for the new window position fbf_update( p_new , l_new , p_new + npixels, l_new + nlines ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] refresh new new window\n", __FUNCTION__ ); #endif #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif return 0; } // end dev_fbf_move_window() ///////////////////////////////////////////// error_t dev_fbf_resize_window( uint32_t wid, uint32_t width, uint32_t height ) { thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if DEBUG_DEV_FBF uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters : wid %d / width %d / height %d / cycle %d\n", __FUNCTION__ , process->pid , this->trdid , wid, width , height , cycle ); #endif // get extended pointer on window to be resized xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointers on windows lock and root xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); // get cluster and local pointer on target window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // get process owner PID, width, height, and buffer uint32_t p_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) ); uint32_t l_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) ); uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) ); uint32_t npixels = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) ); void * base = hal_remote_lpt( XPTR( window_cxy , &window_ptr->buffer ) ); // build extended pointer on window xlist_entry xptr_t xlist_entry_xp = XPTR( window_cxy , &window_ptr->xlist ); // does nothing if no change if( (width == npixels) && (height == nlines) ) return 0; // compute old_size and new size uint32_t old_size = nlines * npixels; uint32_t new_size = width * height; // 1. set the "hidden" flag in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , true ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] hidden set\n", __FUNCTION__ ); #endif // 2. refresh the FBF for the current window size fbf_update( p_min , l_min , p_min + npixels, l_min + nlines ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] refreshed old window\n", __FUNCTION__ ); #endif // 3. take the lock protecting windows in write mode remote_rwlock_wr_acquire( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock taken\n", __FUNCTION__ ); #endif // 4. set the new width & height in the window descriptor, hal_remote_s32( XPTR( window_cxy , &window_ptr->width ), width ); hal_remote_s32( XPTR( window_cxy , &window_ptr->height ), height ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] width & height updated\n", __FUNCTION__ ); #endif // 5. resize vseg if required vmm_global_resize_vseg( process, (intptr_t)base, (intptr_t)base, width * height ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] vseg resized\n", __FUNCTION__ ); #endif // 6. fill buffer extension if required if( new_size > old_size ) memset( base + old_size , 0 , new_size - old_size ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] buffer extension initialized\n", __FUNCTION__ ); #endif // 7. gives the window the highest priority xlist_unlink( xlist_entry_xp ); xlist_add_last( windows_root_xp , xlist_entry_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] set high priority\n", __FUNCTION__ ); #endif // 8. release the lock protecting windows in write mode remote_rwlock_wr_release( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock released\n", __FUNCTION__ ); #endif // 9. reset the "hidden" flag in window descriptor hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , false ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] hidden reset\n", __FUNCTION__ ); #endif // 10. refresh the FBF for the new window position fbf_update( p_min , l_min , p_min + width, l_min + height ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] refreshed new window\n", __FUNCTION__ ); #endif #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , process->pid, this->trdid, cycle ); #endif return 0; } // end dev_fbf_resize_window() ////////////////////////////////////////////// error_t dev_fbf_refresh_window( uint32_t wid, uint32_t line_min, uint32_t line_max ) { #if DEBUG_DEV_FBF thread_t * thi = CURRENT_THREAD; uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters for wid %d / first %d / last %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid, line_min, line_max, cycle ); #endif // get extended pointer on window to be refreshed xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and local pointer on target window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // get p_min, l_min, nlines & npixels from window descriptor uint32_t p_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) ); uint32_t l_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) ); uint32_t npixels = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) ); uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) ); // check and arguments if( (line_min >= nlines) || (line_max > nlines) || (line_min >= line_max) ) { printk("\n[ERROR] in %s : illegal arguments / l_first %d / l_last %d / nlines %d\n", __FUNCTION__, line_min, line_max, nlines ); return -1; } // update FBF fbf_update( p_min , l_min + line_min , p_min + npixels , l_min + line_max ); #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit for wid %d / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, wid, cycle ); #endif return 0; } // end dev_fbf_refresh_window() //////////////////////////////////////////// error_t dev_fbf_front_window( uint32_t wid ) { #if DEBUG_DEV_FBF thread_t * this = CURRENT_THREAD; uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] enters for wid %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid, cycle ); #endif // get extended pointer on window to be refreshed xptr_t window_xp = dev_fbf_get_xptr_from_wid( wid ); if( window_xp == XPTR_NULL ) return -1; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointer on windows lock and root xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); // get cluster and local pointers on window cxy_t window_cxy = GET_CXY( window_xp ); fbf_window_t * window_ptr = GET_PTR( window_xp ); // get target window coordinates, width, height, and hidden uint32_t p_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) ); uint32_t l_min = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) ); uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) ); uint32_t npixels = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) ); bool_t hidden = hal_remote_l32( XPTR( window_cxy , &window_ptr->hidden ) ); // build extended pointer on window xlist_entry xptr_t xlist_entry_xp = XPTR( window_cxy , &window_ptr->xlist ); // 1. take the lock protecting windows in write mode remote_rwlock_wr_acquire( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock taken\n", __FUNCTION__ ); #endif // 2. gives the window the highest priority xlist_unlink( xlist_entry_xp ); xlist_add_last( windows_root_xp , xlist_entry_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] set high priority \n", __FUNCTION__ ); #endif // 3. release the lock protecting windows from write mode remote_rwlock_wr_release( windows_lock_xp ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] lock released\n", __FUNCTION__ ); #endif // 4. update the FBF for this window when not hidden if( hidden == false ) fbf_update( p_min , l_min , p_min + npixels, l_min + nlines ); #if ( DEBUG_DEV_FBF & 1 ) printk("\n[%s] refresh window in FBF\n", __FUNCTION__ ); #endif #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit for wid %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, wid, cycle ); #endif return 0; } // end dev_fbf_front_window() ///////////////////////////////////////// void dev_fbf_display_windows( pid_t pid ) { xptr_t iter_xp; // display header printk("\n***** registered FBF windows *****\n" " wid | hide | lzero | pzero | lines | pixel | pid\n" ); // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointer on windows lock and root xptr_t lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); // take the lock in read mode remote_rwlock_rd_acquire( lock_xp ); XLIST_FOREACH_BACKWARD( root_xp , iter_xp ) { xptr_t w_xp = XLIST_ELEMENT( iter_xp , fbf_window_t , xlist ); fbf_window_t * w_ptr = GET_PTR( w_xp ); cxy_t w_cxy = GET_CXY( w_xp ); uint32_t wid = hal_remote_l32( XPTR( w_cxy , &w_ptr->wid ) ); uint32_t owner_pid = hal_remote_l32( XPTR( w_cxy , &w_ptr->pid ) ); uint32_t hide = hal_remote_l32( XPTR( w_cxy , &w_ptr->hidden ) ); uint32_t lzero = hal_remote_l32( XPTR( w_cxy , &w_ptr->l_min ) ); uint32_t pzero = hal_remote_l32( XPTR( w_cxy , &w_ptr->p_min ) ); uint32_t lines = hal_remote_l32( XPTR( w_cxy , &w_ptr->height ) ); uint32_t pixels = hal_remote_l32( XPTR( w_cxy , &w_ptr->width ) ); if( (pid == 0) || (pid == owner_pid) ) { printk("%d\t | %d\t | %d\t | %d\t | %d\t | %d\t | %x\n", wid, hide, lzero, pzero, lines, pixels, pid ); } } // release the lock remote_rwlock_rd_release( lock_xp ); } // end dev_fbf_display_windows() ///////////////////////////////// void dev_fbf_cleanup( pid_t pid ) { xptr_t iter_xp; // get cluster and pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // build extended pointer on windows lock and root xptr_t lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock ); xptr_t root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root ); // take the lock in read mode remote_rwlock_rd_acquire( lock_xp ); XLIST_FOREACH( root_xp , iter_xp ) { xptr_t w_xp = XLIST_ELEMENT( iter_xp , fbf_window_t , xlist ); fbf_window_t * w_ptr = GET_PTR( w_xp ); cxy_t w_cxy = GET_CXY( w_xp ); // get owner process PID and WID uint32_t owner_pid = hal_remote_l32( XPTR( w_cxy , &w_ptr->pid ) ); uint32_t wid = hal_remote_l32( XPTR( w_cxy , &w_ptr->wid ) ); // delete matching window if( pid == owner_pid ) dev_fbf_delete_window( wid ); } // release the lock from read mode remote_rwlock_rd_release( lock_xp ); } // end dev_fbf_cleanup() /////////////////////////////////////////////// // TODO Deprecated : january 2020 [AG] /////////////////////////////////////////////// error_t dev_fbf_move_data( bool_t is_write, void * user_buffer, uint32_t npixels, uint32_t offset ) { // get pointer on calling thread thread_t * this = CURRENT_THREAD; #if DEBUG_DEV_FBF uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] : buffer %x / npixels %d / offset %x / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, user_buffer, npixels, offset, cycle ); #endif // get pointers on FBF chdev xptr_t fbf_xp = chdev_dir.fbf[0]; cxy_t fbf_cxy = GET_CXY( fbf_xp ); chdev_t * fbf_ptr = GET_PTR( fbf_xp ); // get frame buffer width and height uint32_t width = hal_remote_l32 ( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) ); uint32_t height = hal_remote_l32 ( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) ); // check offset and npixels versus FBF size if( ((offset + npixels) > (width * height)) ) { printk("\n[ERROR] in %s : offset (%d) + npixels (%d) / width (%d) / height (%d)\n", __FUNCTION__, offset, npixels, width, height ); return -1; } // register command in calling thread descriptor this->fbf_cmd.dev_xp = fbf_xp; this->fbf_cmd.type = is_write ? FBF_DRIVER_USER_WRITE : FBF_DRIVER_USER_READ; this->fbf_cmd.buffer = user_buffer; this->fbf_cmd.offset = offset; this->fbf_cmd.npixels = npixels; // get driver command function dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( fbf_cxy , &fbf_ptr->cmd ) ); // call driver cmd( XPTR( local_cxy , this ) ); error_t error = this->fbf_cmd.error; #if DEBUG_DEV_FBF cycle = (uint32_t)hal_get_cycles(); if( DEBUG_DEV_FBF < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif // return I/O operation status return error; } // end dev_fbf_move_data()