vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / ati / overlay.cpp
blob53479f8c6798faa123d7757ac760eac66b359d71
1 /*
2 Copyright 2011 Haiku, Inc. All rights reserved.
3 Distributed under the terms of the MIT license.
5 Authors:
6 Gerald Zajac
7 */
9 #include "accelerant.h"
10 #include "rage128.h"
12 #include <stdlib.h>
16 uint32
17 OverlayCount(const display_mode* mode)
19 (void)mode; // avoid compiler warning for unused arg
21 return 1;
25 const uint32*
26 OverlaySupportedSpaces(const display_mode* mode)
28 (void)mode; // avoid compiler warning for unused arg
30 static const uint32 kSupportedSpaces[] = {B_YCbCr422, 0};
32 return kSupportedSpaces;
36 uint32
37 OverlaySupportedFeatures(uint32 colorSpace)
39 (void)colorSpace; // avoid compiler warning for unused arg
41 return B_OVERLAY_COLOR_KEY
42 | B_OVERLAY_HORIZONTAL_FILTERING
43 | B_OVERLAY_VERTICAL_FILTERING;
47 const overlay_buffer*
48 AllocateOverlayBuffer(color_space colorSpace, uint16 width, uint16 height)
50 SharedInfo& si = *gInfo.sharedInfo;
52 TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n",
53 width, height, colorSpace);
55 // If Mach 64 chip, check hardware limits.
57 if (MACH64_FAMILY(si.chipType)) {
58 if (height > 2048 || width > 768
59 || (width > 384 && si.chipType < MACH64_264VTB)
60 || (width > 720 && (si.chipType < MACH64_264GTPRO
61 || si.chipType > MACH64_264LTPRO)))
62 return NULL;
65 si.overlayLock.Acquire();
67 // Note: When allocating buffers, buffer allocation starts at the end of
68 // video memory, and works backward to the end of the video frame buffer.
69 // The allocated buffers are recorded in a linked list of OverlayBuffer
70 // objects which are ordered by the buffer address with the first object
71 // in the list having the highest buffer address.
73 if (colorSpace != B_YCbCr422) {
74 si.overlayLock.Release();
75 TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
76 colorSpace);
77 return NULL;
80 uint32 bytesPerPixel = 2; // B_YCbCr422 uses 2 bytes per pixel
82 // Calculate required buffer size as a multiple of 1K.
83 uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
85 OverlayBuffer* ovBuff = si.overlayBuffer;
86 OverlayBuffer* prevOvBuff = NULL;
88 // If no buffers have been allocated, prevBuffAddr calculated here will be
89 // the address where the buffer area will start. Leave a gap of about 4K
90 // between where the overlay buffers will start and the cursor image;
91 // thus, if the overlay buffer overflows it will be less apt to affect the
92 // cursor.
94 uint32 prevBuffAddr = (si.videoMemAddr + si.cursorOffset - 0xfff) & ~0xfff;
96 while (ovBuff != NULL) {
97 // Test if there is sufficient space between the end of the current
98 // buffer and the start of the previous buffer to allocate the new
99 // buffer.
101 uint32 currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
102 if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
103 break; // sufficient space for the new buffer
105 prevBuffAddr = (uint32)ovBuff->buffer;
106 prevOvBuff = ovBuff;
107 ovBuff = ovBuff->nextBuffer;
110 OverlayBuffer* nextOvBuff = ovBuff;
112 if (ovBuff == NULL) {
113 // No space between any current buffers of the required size was found;
114 // thus space must be allocated between the last buffer and the end of
115 // the video frame buffer. Compute where current video frame buffer
116 // ends so that it can be determined if there is sufficient space for
117 // the new buffer to be created.
119 uint32 fbEndAddr = si.videoMemAddr + si.frameBufferOffset
120 + (si.displayMode.virtual_width
121 * ((si.displayMode.bitsPerPixel + 7) / 8) // bytes per pixel
122 * si.displayMode.virtual_height);
124 if (buffSize > prevBuffAddr - fbEndAddr) {
125 si.overlayLock.Release();
126 TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) "
127 "byte buffer\n", buffSize, buffSize);
128 return NULL; // insufficient space for buffer
131 nextOvBuff = NULL;
134 ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
135 if (ovBuff == NULL) {
136 si.overlayLock.Release();
137 return NULL; // memory not available for OverlayBuffer struct
140 ovBuff->nextBuffer = nextOvBuff;
141 ovBuff->size = buffSize;
142 ovBuff->space = colorSpace;
143 ovBuff->width = width;
144 ovBuff->height = height;
145 ovBuff->bytes_per_row = width * bytesPerPixel;
146 ovBuff->buffer = (void*)(prevBuffAddr - buffSize);
147 ovBuff->buffer_dma = (void*)(si.videoMemPCI
148 + ((addr_t)ovBuff->buffer - si.videoMemAddr));
150 if (prevOvBuff == NULL)
151 si.overlayBuffer = ovBuff;
152 else
153 prevOvBuff->nextBuffer = ovBuff;
155 si.overlayLock.Release();
156 TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n",
157 buffSize, buffSize, ovBuff->buffer);
158 return ovBuff;
162 status_t
163 ReleaseOverlayBuffer(const overlay_buffer* buffer)
165 SharedInfo& si = *gInfo.sharedInfo;
167 if (buffer == NULL)
168 return B_BAD_VALUE;
170 // Find the buffer to be released.
172 OverlayBuffer* ovBuff = si.overlayBuffer;
173 OverlayBuffer* prevOvBuff = NULL;
175 while (ovBuff != NULL) {
176 if (ovBuff->buffer == buffer->buffer) {
177 // Buffer to be released has been found. Remove the OverlayBuffer
178 // object from the chain of overlay buffers.
180 if (prevOvBuff == NULL)
181 si.overlayBuffer = ovBuff->nextBuffer;
182 else
183 prevOvBuff->nextBuffer = ovBuff->nextBuffer;
185 free(ovBuff);
186 return B_OK;
189 prevOvBuff = ovBuff;
190 ovBuff = ovBuff->nextBuffer;
193 TRACE("ReleaseOverlayBuffer() buffer to release at 0x%lx not found\n",
194 buffer->buffer);
195 return B_ERROR; // buffer to be released not found in chain of buffers
199 status_t
200 GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
201 overlay_constraints* constraints)
203 if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
204 return B_ERROR;
206 // Position (values are in pixels)
207 constraints->view.h_alignment = 0;
208 constraints->view.v_alignment = 0;
210 if (buffer->space == B_YCbCr422)
211 constraints->view.width_alignment = 7;
212 else {
213 TRACE("GetOverlayConstraints() color space 0x%x out of range\n",
214 buffer->space);
215 return B_BAD_VALUE;
218 constraints->view.height_alignment = 0;
220 //Size
221 constraints->view.width.min = 4;
222 constraints->view.height.min = 4;
223 constraints->view.width.max = buffer->width;
224 constraints->view.height.max = buffer->height;
226 // Scaler output restrictions
227 constraints->window.h_alignment = 0;
228 constraints->window.v_alignment = 0;
229 constraints->window.width_alignment = 0;
230 constraints->window.height_alignment = 0;
231 constraints->window.width.min = 2;
232 constraints->window.width.max = mode->virtual_width;
233 constraints->window.height.min = 2;
234 constraints->window.height.max = mode->virtual_height;
236 constraints->h_scale.min = 1.0;
237 constraints->h_scale.max = 8.0;
238 constraints->v_scale.min = 1.0;
239 constraints->v_scale.max = 8.0;
241 return B_OK;
245 overlay_token
246 AllocateOverlay(void)
248 SharedInfo& si = *gInfo.sharedInfo;
250 // There is only a single overlay channel; thus, check if it is already
251 // allocated.
253 if (atomic_or(&si.overlayAllocated, 1) != 0) {
254 TRACE("AllocateOverlay() overlay channel already in use\n");
255 return NULL;
258 return (overlay_token)++si.overlayToken;
262 status_t
263 ReleaseOverlay(overlay_token overlayToken)
265 SharedInfo& si = *gInfo.sharedInfo;
267 if (overlayToken != (overlay_token)si.overlayToken) {
268 TRACE("ReleaseOverlay() error - no overlay previously allocated\n");
269 return B_BAD_VALUE;
272 if (MACH64_FAMILY(si.chipType))
273 Mach64_StopOverlay();
274 else
275 Rage128_StopOverlay();
277 atomic_and(&si.overlayAllocated, 0); // mark overlay as unallocated
278 return B_OK;
282 status_t
283 ConfigureOverlay(overlay_token overlayToken, const overlay_buffer* buffer,
284 const overlay_window* window, const overlay_view* view)
286 SharedInfo& si = *gInfo.sharedInfo;
288 if (overlayToken != (overlay_token)si.overlayToken)
289 return B_BAD_VALUE;
291 if (buffer == NULL)
292 return B_BAD_VALUE;
294 if (window == NULL || view == NULL) {
295 if (MACH64_FAMILY(si.chipType))
296 Mach64_StopOverlay();
297 else
298 Rage128_StopOverlay();
300 return B_OK;
303 // Program the overlay hardware.
304 if (MACH64_FAMILY(si.chipType)) {
305 if (!Mach64_DisplayOverlay(window, buffer)) {
306 TRACE("ConfigureOverlay(), call to Mach64_DisplayOverlay() "
307 "returned error\n");
308 return B_ERROR;
310 } else {
311 if (!Rage128_DisplayOverlay(window, buffer)) {
312 TRACE("ConfigureOverlay(), call to Rage128_DisplayOverlay() "
313 "returned error\n");
314 return B_ERROR;
318 return B_OK;