vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon / Cursor.c
blob0e09752c7d59bce2d6e4eee0d5b3da0ace4b2963
1 /*
2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Hardware cursor support.
8 */
11 #include "radeon_accelerant.h"
12 #include "GlobalData.h"
13 #include "generic.h"
14 #include "mmio.h"
15 #include "crtc_regs.h"
17 static void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y );
19 // set standard foreground/background colours
20 void Radeon_SetCursorColors( accelerator_info *ai, int crtc_idx )
22 SHOW_FLOW0( 3, "" );
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 );
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)
37 virtual_card *vc = ai->vc;
38 uint8 *fb_cursor = vc->cursor.data;
39 int row, col_byte;
41 /* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */
42 /* if( width != 16 || height != 16 )
43 return B_ERROR;*/
45 if( hot_x >= width || hot_y >= height )
46 return B_ERROR;
48 // TBD: should we sync here? I'd say so, but if I fail, we deadlock
50 vc->cursor.hot_x = hot_x;
51 vc->cursor.hot_y = hot_y;
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;
65 return B_OK;
69 // public function to move cursor
70 void MOVE_CURSOR(uint16 x, uint16 y)
72 virtual_card *vc = ai->vc;
73 bool move_screen = false;
74 uint16 hds, vds;
76 // alignment mask for horizontal position
77 uint16 h_adjust = 7;
79 ACQUIRE_BEN( ai->si->engine.lock );
81 hds = vc->mode.h_display_start;
82 vds = vc->mode.v_display_start;
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;
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;
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;
108 if( move_screen )
109 Radeon_MoveDisplay( ai, hds, vds );
112 // adjust according to virtual screen position
113 x -= hds;
114 y -= vds;
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 );
122 RELEASE_BEN( ai->si->engine.lock );
126 // public function to show cursor
127 void SHOW_CURSOR( bool is_visible )
129 virtual_card *vc = ai->vc;
131 SHOW_FLOW0( 4, "" );
133 ACQUIRE_BEN( ai->si->engine.lock );
135 // this is the public statement
136 vc->cursor.is_visible = is_visible;
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 );
145 RELEASE_BEN( ai->si->engine.lock );
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 )
153 virtual_card *vc = ai->vc;
154 crtc_info *crtc = &ai->si->crtc[crtc_idx];
155 int xorigin, yorigin;
156 bool prev_state;
158 // adjust according to relative screen position
159 x -= crtc->rel_x;
160 y -= crtc->rel_y;
162 // and to hot spot
163 x -= vc->cursor.hot_x;
164 y -= vc->cursor.hot_y;
166 // check whether the cursor is (partially) visible on this screen
167 prev_state = crtc->cursor_on_screen;
168 crtc->cursor_on_screen = true;
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 )
176 crtc->cursor_on_screen = false;
179 if( prev_state != crtc->cursor_on_screen )
180 Radeon_ShowCursor( ai, crtc_idx );
182 if( !crtc->cursor_on_screen )
183 return;
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;
190 if( x < 0 )
191 xorigin = -x;
193 if( y < 0 )
194 yorigin = -y;
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 );
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 )
222 virtual_card *vc = ai->vc;
223 crtc_info *crtc = &ai->si->crtc[crtc_idx];
224 uint32 tmp;
226 if( crtc_idx == 0 ) {
227 tmp = INREG( ai->regs, RADEON_CRTC_GEN_CNTL );
229 if( vc->cursor.is_visible && crtc->cursor_on_screen ) {
230 tmp |= RADEON_CRTC_CUR_EN;
231 } else {
232 tmp &= ~RADEON_CRTC_CUR_EN;
235 OUTREG( ai->regs, RADEON_CRTC_GEN_CNTL, tmp );
237 } else {
238 tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
240 if( vc->cursor.is_visible && crtc->cursor_on_screen )
241 tmp |= RADEON_CRTC2_CUR_EN;
242 else
243 tmp &= ~RADEON_CRTC2_CUR_EN;
245 OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp );