1 /****************************************************************************** 2 / 3 / File: Capture.cpp 4 / 5 / Description: ATI Radeon Capture Unit interface. 6 / 7 / Copyright 2001, Carlos Hasan 8 / 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 12 / 13 *******************************************************************************/ 14 15 #include <Debug.h> 16 #include "Capture.h" 17 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() 31 { 32 PRINT(("CCapture::CCapture()\n")); 33 } 34 35 CCapture::~CCapture() 36 { 37 PRINT(("CCapture::~CCapture()\n")); 38 } 39 40 status_t CCapture::InitCheck() const 41 { 42 return fRadeon.InitCheck(); 43 } 44 45 void CCapture::SetBuffer(capture_stream_format format, capture_buffer_mode mode, 46 int offset0, int offset1, int size, int pitch) 47 { 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)); 53 54 fMode = mode; 55 fFormat = format; 56 fOffset0 = offset0 + fRadeon.VirtualMemoryBase(); 57 fOffset1 = offset1 + fRadeon.VirtualMemoryBase(); 58 fSize = size; 59 fPitch = pitch; 60 } 61 62 void CCapture::SetClip(int left, int top, int right, int bottom) 63 { 64 PRINT(("CCapture::SetClip(%d, %d, %d, %d)\n", 65 left, top, right, bottom)); 66 67 fClip.SetTo(left, top, right, bottom); 68 } 69 70 void CCapture::SetVBIBuffer(int offset0, int offset1, int size) 71 { 72 PRINT(("CCapture::SetVBIBuffer(0x%08x, 0x%08x, %d)\n", offset0, offset1, size)); 73 74 fVBIOffset0 = offset0 + fRadeon.VirtualMemoryBase(); 75 fVBIOffset1 = offset1 + fRadeon.VirtualMemoryBase(); 76 fVBISize = size; 77 } 78 79 void CCapture::SetVBIClip(int left, int top, int right, int bottom) 80 { 81 PRINT(("CCapture::SetVBIClip(%d, %d, %d, %d)\n", 82 left, top, right, bottom)); 83 84 fVBIClip.SetTo(left, top, right, bottom); 85 } 86 87 void CCapture::Start(bool vbi) 88 { 89 PRINT(("CCapture::Start(%d)\n", vbi)); 90 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); 94 95 // select buffer offset and pitch 96 //fRadeon.WaitForFifo(5); 97 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; 104 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; 111 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; 118 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; 127 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; 134 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; 143 } 144 145 // select VBI buffer offset 146 //fRadeon.WaitForFifo(4); 147 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); 151 152 SetRegister(C_RADEON_CAP0_VBI2_OFFSET, fVBIOffset1); 153 SetRegister(C_RADEON_CAP0_VBI3_OFFSET, fVBIOffset1 + fVBISize); 154 155 // select capture clipping window 156 //fRadeon.WaitForFifo(2); 157 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)); 161 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)); 165 166 // select VBI clipping window 167 //fRadeon.WaitForFifo(2); 168 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)); 172 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)); 176 177 // select buffer type, input mode, video format and buffering mode 178 //fRadeon.WaitForFifo(10); 179 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; 186 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; 192 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; 198 } 199 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; 206 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; 212 } 213 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); 217 218 219 // select stream format and port mode 220 //fRadeon.WaitForFifo(4); 221 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; 239 } 240 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); 251 252 // prepare to enable capture 253 //fRadeon.WaitForFifo(14); 254 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); 259 260 // connect capture engine to AMC connector 261 SetRegister(C_RADEON_VIDEOMUX_CNTL, 1, 1); 262 263 // select capture engine clock source to PCLK 264 SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_PCLK); 265 266 // enable capture unit 267 SetRegister(C_RADEON_CAP0_TRIG_CNTL, 268 C_RADEON_CAP0_TRIGGER_W_CAPTURE | C_RADEON_CAP0_EN); 269 270 // enable VBI capture 271 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_EN, 272 (vbi ? C_RADEON_CAP0_VBI_EN : 0)); 273 } 274 275 void CCapture::Stop() 276 { 277 PRINT(("CCapture::Stop()\n")); 278 279 // disable capture unit 280 //fRadeon.WaitForFifo(4); 281 282 // disable capture unit 283 SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION); 284 285 // disable the capture engine clock (set to ground) 286 fRadeon.SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_GND); 287 } 288 289 void CCapture::SetInterrupts(bool enable) 290 { 291 PRINT(("CCapture::SetInterrupts(%d)\n", enable)); 292 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)); 300 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); 306 } 307 308 int CCapture::WaitInterrupts(int * sequence, bigtime_t * when, bigtime_t timeout) 309 { 310 int mask; 311 312 if (fRadeon.WaitInterrupt(&mask, sequence, when, timeout) == B_OK) { 313 /* 314 int mask = fRadeon.Register(C_RADEON_CAP_INT_STATUS); 315 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); 320 */ 321 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); 329 } 330 return 0; 331 } 332 333 int CCapture::Register(radeon_register index, int mask) 334 { 335 return fRadeon.Register(index, mask); 336 } 337 338 void CCapture::SetRegister(radeon_register index, int value) 339 { 340 fRadeon.SetRegister(index, value); 341 } 342 343 void CCapture::SetRegister(radeon_register index, int mask, int value) 344 { 345 fRadeon.SetRegister(index, mask, value); 346 } 347