vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / radeon / Capture.cpp
blob5179f2a34f33606c199db01abb742561bd399241
1 /******************************************************************************
3 / File: Capture.cpp
5 / Description: ATI Radeon Capture Unit interface.
7 / Copyright 2001, Carlos Hasan
9 / TK: something about synchronization: I removed all the FIFO wait
10 / functions as they aren't thread-safe and AFAIK not needed as
11 / only 2D/3D register accesses are buffered
13 *******************************************************************************/
15 #include <Debug.h>
16 #include "Capture.h"
18 CCapture::CCapture(CRadeon & radeon)
19 : fRadeon(radeon),
20 fMode(C_RADEON_CAPTURE_FIELD_SINGLE),
21 fFormat(C_RADEON_CAPTURE_CCIR656),
22 fOffset0(0),
23 fOffset1(0),
24 fVBIOffset0(0),
25 fVBIOffset1(0),
26 fSize(0),
27 fVBISize(0),
28 fPitch(0),
29 fClip(),
30 fVBIClip()
32 PRINT(("CCapture::CCapture()\n"));
35 CCapture::~CCapture()
37 PRINT(("CCapture::~CCapture()\n"));
40 status_t CCapture::InitCheck() const
42 return fRadeon.InitCheck();
45 void CCapture::SetBuffer(capture_stream_format format, capture_buffer_mode mode,
46 int offset0, int offset1, int size, int pitch)
48 PRINT(("CCapture::SetBuffer(%s, %s, 0x%08x, 0x%08x, 0x%08x, %d)\n",
49 "BROOKTREE\0CCIR656\0\0\0ZVIDEO\0\0\0\0VIP"+10*format,
50 "FIELD-SINGLE\0FIELD-DOUBLE\0BOB-SINGLE\0\0\0"
51 "BOB-DOUBLE\0\0\0WEAVE-SINGLE\0WEAVE-DOUBLE"+13*mode,
52 offset0, offset1, size, pitch));
54 fMode = mode;
55 fFormat = format;
56 fOffset0 = offset0 + fRadeon.VirtualMemoryBase();
57 fOffset1 = offset1 + fRadeon.VirtualMemoryBase();
58 fSize = size;
59 fPitch = pitch;
62 void CCapture::SetClip(int left, int top, int right, int bottom)
64 PRINT(("CCapture::SetClip(%d, %d, %d, %d)\n",
65 left, top, right, bottom));
67 fClip.SetTo(left, top, right, bottom);
70 void CCapture::SetVBIBuffer(int offset0, int offset1, int size)
72 PRINT(("CCapture::SetVBIBuffer(0x%08x, 0x%08x, %d)\n", offset0, offset1, size));
74 fVBIOffset0 = offset0 + fRadeon.VirtualMemoryBase();
75 fVBIOffset1 = offset1 + fRadeon.VirtualMemoryBase();
76 fVBISize = size;
79 void CCapture::SetVBIClip(int left, int top, int right, int bottom)
81 PRINT(("CCapture::SetVBIClip(%d, %d, %d, %d)\n",
82 left, top, right, bottom));
84 fVBIClip.SetTo(left, top, right, bottom);
87 void CCapture::Start(bool vbi)
89 PRINT(("CCapture::Start(%d)\n", vbi));
91 // initially the capture unit is disabled
92 //fRadeon.WaitForFifo(2);
93 SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
95 // select buffer offset and pitch
96 //fRadeon.WaitForFifo(5);
98 switch (fMode) {
99 case C_RADEON_CAPTURE_FIELD_SINGLE:
100 /* capture single field, single buffer */
101 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
102 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
103 break;
105 case C_RADEON_CAPTURE_FIELD_DOUBLE:
106 /* capture single field, double buffer */
107 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
108 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
109 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
110 break;
112 case C_RADEON_CAPTURE_BOB_SINGLE:
113 /* capture interlaced frame, single buffer */
114 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
115 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
116 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
117 break;
119 case C_RADEON_CAPTURE_BOB_DOUBLE:
120 /* capture interlaced frame, double buffer */
121 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
122 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
123 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
124 SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + fSize);
125 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
126 break;
128 case C_RADEON_CAPTURE_WEAVE_SINGLE:
129 /* capture deinterlaced frame, single buffer */
130 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
131 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
132 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
133 break;
135 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
136 /* capture deinterlaced frame, double buffer */
137 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
138 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
139 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
140 SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + (fPitch << 1));
141 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
142 break;
145 // select VBI buffer offset
146 //fRadeon.WaitForFifo(4);
148 // FIXME: change according to the buffering mode?
149 SetRegister(C_RADEON_CAP0_VBI0_OFFSET, fVBIOffset0);
150 SetRegister(C_RADEON_CAP0_VBI1_OFFSET, fVBIOffset0 + fVBISize);
152 SetRegister(C_RADEON_CAP0_VBI2_OFFSET, fVBIOffset1);
153 SetRegister(C_RADEON_CAP0_VBI3_OFFSET, fVBIOffset1 + fVBISize);
155 // select capture clipping window
156 //fRadeon.WaitForFifo(2);
158 SetRegister(C_RADEON_CAP0_H_WINDOW,
159 ((fClip.Left() << 1) & C_RADEON_CAP0_H_START) |
160 ((fClip.Width() << 17) & C_RADEON_CAP0_H_WIDTH));
162 SetRegister(C_RADEON_CAP0_V_WINDOW,
163 ((fClip.Top() << 0) & C_RADEON_CAP0_V_START) |
164 ((fClip.Bottom() << 16) & C_RADEON_CAP0_V_END));
166 // select VBI clipping window
167 //fRadeon.WaitForFifo(2);
169 SetRegister(C_RADEON_CAP0_VBI_H_WINDOW,
170 ((fVBIClip.Left() << 0) & C_RADEON_CAP0_VBI_H_START) |
171 ((fVBIClip.Width() << 16) & C_RADEON_CAP0_VBI_H_WIDTH));
173 SetRegister(C_RADEON_CAP0_VBI_V_WINDOW,
174 ((fVBIClip.Top() << 0) & C_RADEON_CAP0_VBI_V_START) |
175 ((fVBIClip.Bottom() << 16) & C_RADEON_CAP0_VBI_V_END));
177 // select buffer type, input mode, video format and buffering mode
178 //fRadeon.WaitForFifo(10);
180 switch (fMode) {
181 case C_RADEON_CAPTURE_FIELD_SINGLE:
182 case C_RADEON_CAPTURE_FIELD_DOUBLE:
183 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FIELD);
184 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
185 break;
187 case C_RADEON_CAPTURE_BOB_SINGLE:
188 case C_RADEON_CAPTURE_BOB_DOUBLE:
189 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_ALTERNATING);
190 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
191 break;
193 case C_RADEON_CAPTURE_WEAVE_SINGLE:
194 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
195 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FRAME);
196 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FRAME);
197 break;
200 switch (fMode) {
201 case C_RADEON_CAPTURE_FIELD_SINGLE:
202 case C_RADEON_CAPTURE_BOB_SINGLE:
203 case C_RADEON_CAPTURE_WEAVE_SINGLE:
204 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_SINGLE);
205 break;
207 case C_RADEON_CAPTURE_FIELD_DOUBLE:
208 case C_RADEON_CAPTURE_BOB_DOUBLE:
209 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
210 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_DOUBLE);
211 break;
214 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_INPUT_MODE, C_RADEON_CAP0_INPUT_MODE_CONTINUOUS);
215 SetRegister(C_RADEON_CAP0_CONFIG,
216 C_RADEON_CAP0_VIDEO_IN_FORMAT | C_RADEON_CAP0_VIDEO_SIGNED_UV, C_RADEON_CAP0_VIDEO_IN_VYUY422);
219 // select stream format and port mode
220 //fRadeon.WaitForFifo(4);
222 switch (fFormat) {
223 case C_RADEON_CAPTURE_BROOKTREE:
224 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_BROOKTREE);
225 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
226 break;
227 case C_RADEON_CAPTURE_CCIR656:
228 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_CCIR656);
229 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
230 break;
231 case C_RADEON_CAPTURE_ZOOMVIDEO:
232 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_ZV);
233 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
234 break;
235 case C_RADEON_CAPTURE_VIP:
236 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_VIP);
237 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
238 break;
241 // set capture mirror mode, field sense, downscaler/decimator, enable 3:4 pull down
242 //fRadeon.WaitForFifo(16);
243 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_MIRROR_EN, 0);
244 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MIRROR_EN, 0);
245 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_START_FIELD, C_RADEON_CAP0_START_ODD_FIELD);
246 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HORZ_DOWN, C_RADEON_CAP0_HORZ_DOWN_1X);
247 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VERT_DOWN, C_RADEON_CAP0_VERT_DOWN_1X);
248 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_HORZ_DOWN, C_RADEON_CAP0_VBI_HORZ_DOWN_1X);
249 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HDWNS_DEC, C_RADEON_CAP0_DECIMATOR);
250 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_SOFT_PULL_DOWN_EN, C_RADEON_CAP0_SOFT_PULL_DOWN_EN);
252 // prepare to enable capture
253 //fRadeon.WaitForFifo(14);
255 // disable test and debug modes
256 SetRegister(C_RADEON_TEST_DEBUG_CNTL, 0);
257 SetRegister(C_RADEON_CAP0_VIDEO_SYNC_TEST, 0);
258 SetRegister(C_RADEON_CAP0_DEBUG, C_RADEON_CAP0_V_SYNC);
260 // connect capture engine to AMC connector
261 SetRegister(C_RADEON_VIDEOMUX_CNTL, 1, 1);
263 // select capture engine clock source to PCLK
264 SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_PCLK);
266 // enable capture unit
267 SetRegister(C_RADEON_CAP0_TRIG_CNTL,
268 C_RADEON_CAP0_TRIGGER_W_CAPTURE | C_RADEON_CAP0_EN);
270 // enable VBI capture
271 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_EN,
272 (vbi ? C_RADEON_CAP0_VBI_EN : 0));
275 void CCapture::Stop()
277 PRINT(("CCapture::Stop()\n"));
279 // disable capture unit
280 //fRadeon.WaitForFifo(4);
282 // disable capture unit
283 SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
285 // disable the capture engine clock (set to ground)
286 fRadeon.SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_GND);
289 void CCapture::SetInterrupts(bool enable)
291 PRINT(("CCapture::SetInterrupts(%d)\n", enable));
293 fRadeon.SetRegister(C_RADEON_CAP_INT_CNTL,
294 C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
295 C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
296 C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN,
297 (enable ? C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
298 C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
299 C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN : 0));
301 // clear any stick interrupt
302 fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
303 C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
304 C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
305 C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
308 int CCapture::WaitInterrupts(int * sequence, bigtime_t * when, bigtime_t timeout)
310 int mask;
312 if (fRadeon.WaitInterrupt(&mask, sequence, when, timeout) == B_OK) {
314 int mask = fRadeon.Register(C_RADEON_CAP_INT_STATUS);
316 fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
317 C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
318 C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
319 C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
322 return
323 ((mask & C_RADEON_CAP0_BUF0_INT) != 0 ? C_RADEON_CAPTURE_BUF0_INT : 0) |
324 ((mask & C_RADEON_CAP0_BUF1_INT) != 0 ? C_RADEON_CAPTURE_BUF1_INT : 0) |
325 ((mask & C_RADEON_CAP0_BUF0_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF0_EVEN_INT : 0) |
326 ((mask & C_RADEON_CAP0_BUF1_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF1_EVEN_INT : 0) |
327 ((mask & C_RADEON_CAP0_VBI0_INT) != 0 ? C_RADEON_CAPTURE_VBI0_INT : 0) |
328 ((mask & C_RADEON_CAP0_VBI1_INT) != 0 ? C_RADEON_CAPTURE_VBI1_INT : 0);
330 return 0;
333 int CCapture::Register(radeon_register index, int mask)
335 return fRadeon.Register(index, mask);
338 void CCapture::SetRegister(radeon_register index, int value)
340 fRadeon.SetRegister(index, value);
343 void CCapture::SetRegister(radeon_register index, int mask, int value)
345 fRadeon.SetRegister(index, mask, value);