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