1 /* 2 Copyright (c) 2002-2004, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Hardware cursor support. 8 */ 9 10 11 #include "radeon_accelerant.h" 12 #include "GlobalData.h" 13 #include "generic.h" 14 #include "mmio.h" 15 #include "crtc_regs.h" 16 17 static void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y ); 18 19 // set standard foreground/background colours 20 void Radeon_SetCursorColors( accelerator_info *ai, int crtc_idx ) 21 { 22 SHOW_FLOW0( 3, "" ); 23 24 if( crtc_idx == 0 ) { 25 OUTREG( ai->regs, RADEON_CUR_CLR0, 0xffffff ); 26 OUTREG( ai->regs, RADEON_CUR_CLR1, 0 ); 27 } else { 28 OUTREG( ai->regs, RADEON_CUR2_CLR0, 0xffffff ); 29 OUTREG( ai->regs, RADEON_CUR2_CLR1, 0 ); 30 } 31 } 32 33 // public function to set shape of cursor 34 status_t SET_CURSOR_SHAPE( uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, 35 uint8 *andMask, uint8 *xorMask) 36 { 37 virtual_card *vc = ai->vc; 38 uint8 *fb_cursor = vc->cursor.data; 39 int row, col_byte; 40 41 /* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */ 42 /* if( width != 16 || height != 16 ) 43 return B_ERROR;*/ 44 45 if( hot_x >= width || hot_y >= height ) 46 return B_ERROR; 47 48 // TBD: should we sync here? I'd say so, but if I fail, we deadlock 49 50 vc->cursor.hot_x = hot_x; 51 vc->cursor.hot_y = hot_y; 52 53 for( row = 0; row < 64; ++row ) { 54 for( col_byte = 0; col_byte < 64 / 8; ++col_byte ) { 55 if( row < height && col_byte < (width + 7) / 8 ) { 56 fb_cursor[row * 64/8 * 2 + col_byte] = *andMask++; 57 fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = *xorMask++; 58 } else { 59 fb_cursor[row * 64/8 * 2 + col_byte] = 0xff; 60 fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = 0; 61 } 62 } 63 } 64 65 return B_OK; 66 } 67 68 69 // public function to move cursor 70 void MOVE_CURSOR(uint16 x, uint16 y) 71 { 72 virtual_card *vc = ai->vc; 73 bool move_screen = false; 74 uint16 hds, vds; 75 76 // alignment mask for horizontal position 77 uint16 h_adjust = 7; 78 79 ACQUIRE_BEN( ai->si->engine.lock ); 80 81 hds = vc->mode.h_display_start; 82 vds = vc->mode.v_display_start; 83 84 // clamp cursor (negative positions are impossible due to uint16) 85 if (x >= vc->mode.virtual_width) 86 x = vc->mode.virtual_width - 1; 87 if (y >= vc->mode.virtual_height) 88 y = vc->mode.virtual_height - 1; 89 90 // if scrolling enabled, i.e. we have a larger virtual screen, 91 // pan display accordingly 92 if( vc->scroll ) { 93 if( x >= (vc->mode.timing.h_display + hds) ) { 94 hds = ((x - vc->mode.timing.h_display) + 1 + h_adjust) & ~h_adjust; 95 move_screen = true; 96 } else if( x < hds ) { 97 hds = x & ~h_adjust; 98 move_screen = true; 99 } 100 if( y >= (vc->mode.timing.v_display + vds) ) { 101 vds = y - vc->mode.timing.v_display + 1; 102 move_screen = true; 103 } else if( y < vds ) { 104 vds = y; 105 move_screen = true; 106 } 107 108 if( move_screen ) 109 Radeon_MoveDisplay( ai, hds, vds ); 110 } 111 112 // adjust according to virtual screen position 113 x -= hds; 114 y -= vds; 115 116 // go 117 if( vc->used_crtc[0] ) 118 moveOneCursor( ai, 0, x, y ); 119 if( vc->used_crtc[1] ) 120 moveOneCursor( ai, 1, x, y ); 121 122 RELEASE_BEN( ai->si->engine.lock ); 123 } 124 125 126 // public function to show cursor 127 void SHOW_CURSOR( bool is_visible ) 128 { 129 virtual_card *vc = ai->vc; 130 131 SHOW_FLOW0( 4, "" ); 132 133 ACQUIRE_BEN( ai->si->engine.lock ); 134 135 // this is the public statement 136 vc->cursor.is_visible = is_visible; 137 138 // the following functions take also care to not 139 // show the cursor if it's on the other port 140 if( vc->used_crtc[0] ) 141 Radeon_ShowCursor( ai, 0 ); 142 if( vc->used_crtc[1] ) 143 Radeon_ShowCursor( ai, 1 ); 144 145 RELEASE_BEN( ai->si->engine.lock ); 146 } 147 148 149 // move cursor on one port 150 // main_port - common data is stored here 151 void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y ) 152 { 153 virtual_card *vc = ai->vc; 154 crtc_info *crtc = &ai->si->crtc[crtc_idx]; 155 int xorigin, yorigin; 156 bool prev_state; 157 158 // adjust according to relative screen position 159 x -= crtc->rel_x; 160 y -= crtc->rel_y; 161 162 // and to hot spot 163 x -= vc->cursor.hot_x; 164 y -= vc->cursor.hot_y; 165 166 // check whether the cursor is (partially) visible on this screen 167 prev_state = crtc->cursor_on_screen; 168 crtc->cursor_on_screen = true; 169 170 // in theory, cursor can be up to 64 pixels off screen, 171 // but there were display errors 172 if( y > crtc->mode.timing.v_display || 173 x > crtc->mode.timing.h_display || 174 x <= -16 || y <= -16 ) 175 { 176 crtc->cursor_on_screen = false; 177 } 178 179 if( prev_state != crtc->cursor_on_screen ) 180 Radeon_ShowCursor( ai, crtc_idx ); 181 182 if( !crtc->cursor_on_screen ) 183 return; 184 185 // if upper-left corner of cursor is outside of 186 // screen, we have to use special registers to clip it 187 xorigin = 0; 188 yorigin = 0; 189 190 if( x < 0 ) 191 xorigin = -x; 192 193 if( y < 0 ) 194 yorigin = -y; 195 196 if( crtc_idx == 0 ) { 197 OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_OFF, RADEON_CUR_LOCK 198 | (xorigin << 16) 199 | yorigin ); 200 OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_POSN, RADEON_CUR_LOCK 201 | ((xorigin ? 0 : x) << 16) 202 | (yorigin ? 0 : y) ); 203 OUTREG( ai->regs, RADEON_CUR_OFFSET, 204 vc->cursor.fb_offset + xorigin + yorigin * 16 ); 205 } else { 206 OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK 207 | (xorigin << 16) 208 | yorigin ); 209 OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_POSN, RADEON_CUR2_LOCK 210 | ((xorigin ? 0 : x) << 16) 211 | (yorigin ? 0 : y) ); 212 OUTREG( ai->regs, RADEON_CUR2_OFFSET, 213 vc->cursor.fb_offset + xorigin + yorigin * 16 ); 214 } 215 } 216 217 218 // show cursor on one port, depending on official whishes and whether 219 // cursor is located on this subscreen 220 void Radeon_ShowCursor( accelerator_info *ai, int crtc_idx ) 221 { 222 virtual_card *vc = ai->vc; 223 crtc_info *crtc = &ai->si->crtc[crtc_idx]; 224 uint32 tmp; 225 226 if( crtc_idx == 0 ) { 227 tmp = INREG( ai->regs, RADEON_CRTC_GEN_CNTL ); 228 229 if( vc->cursor.is_visible && crtc->cursor_on_screen ) { 230 tmp |= RADEON_CRTC_CUR_EN; 231 } else { 232 tmp &= ~RADEON_CRTC_CUR_EN; 233 } 234 235 OUTREG( ai->regs, RADEON_CRTC_GEN_CNTL, tmp ); 236 237 } else { 238 tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL ); 239 240 if( vc->cursor.is_visible && crtc->cursor_on_screen ) 241 tmp |= RADEON_CRTC2_CUR_EN; 242 else 243 tmp &= ~RADEON_CRTC2_CUR_EN; 244 245 OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp ); 246 } 247 } 248