Add video in support included with version 4.1 of the radeon driver.

Feel free to relocate if I have guessed the wrong destination for this stuff.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8407 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shadow303
2004-07-16 00:49:57 +00:00
parent 2a37e4c1cf
commit ffec4cb14d
25 changed files with 10588 additions and 0 deletions
+1
View File
@@ -6,6 +6,7 @@ SubDir OBOS_TOP src add-ons media media-add-ons ;
SubInclude OBOS_TOP src add-ons media media-add-ons legacy ;
SubInclude OBOS_TOP src add-ons media media-add-ons mixer ;
SubInclude OBOS_TOP src add-ons media media-add-ons multi_audio ;
SubInclude OBOS_TOP src add-ons media media-add-ons radeon ;
SubInclude OBOS_TOP src add-ons media media-add-ons tone_producer_demo ;
SubInclude OBOS_TOP src add-ons media media-add-ons video_producer_demo ;
@@ -0,0 +1,828 @@
/******************************************************************************
/
/ File: CC.cpp
/
/ Description: Closed caption module.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <stdio.h>
#include <Debug.h>
#include "CC.h"
CCaption::CCaption(CCapture & capture)
: fCapture(capture),
fChannel(C_RADEON_CC1),
fRow(0),
fColumn(0),
fColor(0),
fLastControlCode(0)
{
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
fText[row][column] = fDisplayText[row][column] = 0x0000;
}
}
}
CCaption::~CCaption()
{
}
status_t CCaption::InitCheck() const
{
return fCapture.InitCheck();
}
void CCaption::SetMode(cc_mode mode)
{
fChannel = mode;
fLastControlCode = 0;
}
bool CCaption::DecodeBits(const unsigned char * buffer, int & data)
{
// assume the buffer is long enough (at least VBI line width bytes)
if (buffer == NULL)
return false;
// compute low/high levels
int low = 0xff, high = 0x00;
for (int offset = C_RADEON_CC_BLANK_START; offset < C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION; offset++) {
if (low > buffer[offset])
low = buffer[offset];
if (high < buffer[offset])
high = buffer[offset];
}
if (low + C_RADEON_CC_LEVEL_THRESHOLD >= high)
return false;
const int middle = (low + high) >> 1;
// find position of the first pulse
int start = C_RADEON_CC_BLANK_START + C_RADEON_CC_BIT_DURATION;
while (start <= C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION) {
if (buffer[start + 0] < middle && buffer[start + 1] < middle &&
buffer[start + 3] > middle && buffer[start + 4] > middle)
break;
start++;
}
if (start >= C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION)
return false;
// compute position of the last pulse
int end = start + 17 * C_RADEON_CC_BIT_DURATION;
// start in middle of first pulse
int bit = 0;
bool one = true;
for (int offset = start + C_RADEON_CC_BIT_DURATION / 2; offset < end; offset++) {
int width = 1;
// search the next pulse front
while (offset < end) {
if (one) {
if (buffer[offset + 0] > middle && buffer[offset + 1] > middle &&
buffer[offset + 3] < middle && buffer[offset + 4] < middle)
break;
}
else {
if (buffer[offset + 0] < middle && buffer[offset + 1] < middle &&
buffer[offset + 3] > middle && buffer[offset + 4] > middle)
break;
}
offset++;
width++;
}
// compute pulse width in bits
const int nbits = (width + (bit == 0 ? 0 : bit == 15 ? C_RADEON_CC_BIT_DURATION :
C_RADEON_CC_BIT_DURATION / 2)) / C_RADEON_CC_BIT_DURATION;
data >>= nbits;
if (one)
data |= (0xffff << (16 - nbits)) & 0xffff;
if ((bit += nbits) >= C_RADEON_CC_BITS_PER_FIELD)
break;
one = !one;
}
if (bit != C_RADEON_CC_BITS_PER_FIELD)
return false;
return true;
}
bool CCaption::Decode(const unsigned char * buffer0,
const unsigned char * buffer1)
{
enum caption_code {
/* channel */
C_CC1 = 0x0000,
C_CC2 = 0x0800,
/* address */
C_ROW_1 = 0x0100,
C_ROW_2 = 0x0120,
C_ROW_3 = 0x0200,
C_ROW_4 = 0x0220,
C_ROW_5 = 0x0500,
C_ROW_6 = 0x0520,
C_ROW_7 = 0x0600,
C_ROW_8 = 0x0620,
C_ROW_9 = 0x0700,
C_ROW_10 = 0x0720,
C_ROW_11 = 0x0000,
C_ROW_12 = 0x0300,
C_ROW_13 = 0x0320,
C_ROW_14 = 0x0400,
C_ROW_15 = 0x0420,
/* color */
C_WHITE = 0x0000,
C_GREEN = 0x0002,
C_BLUE = 0x0004,
C_CYAN = 0x0006,
C_RED = 0x0008,
C_YELLOW = 0x000a,
C_MAGENTA = 0x000c,
C_ITALICS = 0x000e,
/* underline */
C_NORMAL = 0x0000,
C_UNDERLINE = 0x0001,
/* control */
C_RCL = 0x0000, // resume caption loading
C_BS = 0x0001, // backspace
C_AOF = 0x0002, // alarm off
C_AON = 0x0003, // alarm on
C_DER = 0x0004, // delete to end of row
C_RU2 = 0x0005, // roll-up captions (2 rows)
C_RU3 = 0x0006, // roll-up captions (3 rows)
C_RU4 = 0x0007, // roll-up captions (4 rows)
C_FON = 0x0008, // flash on
C_RDC = 0x0009, // resume direct captioning
C_TR = 0x000a, // text restart
C_RTD = 0x000b, // resume text display
C_EDM = 0x000c, // erase displayed memory
C_CR = 0x000d, // carriage return
C_ENM = 0x000e, // erase non-displayed memory
C_EOC = 0x000f, // end of caption
/* special character */
C_reg = 0x0000, // registered
C_deg = 0x0001, // degree
C_frac12 = 0x0002, // fraction 1/2
C_iquest = 0x0003, // invert question
C_trademark = 0x0004, // trademark
C_cent = 0x0005, // cent
C_pound = 0x0006, // pound
C_music = 0x0007, // music note
C_agrave = 0x0008, // agrave
C_tspace = 0x0009, // transparent space
C_egrave = 0x000a, // egrave
C_acirc = 0x000b, // a circ
C_ecirc = 0x000c, // e circ
C_icirc = 0x000d, // i circ
C_ocirc = 0x000e, // o circ
C_ucirc = 0x000f, // u circ
/* standard character (ASCII) */
C_aacute = 0x002a, // a acute accent
C_eacute = 0x005c, // e acute accent
C_iacute = 0x005e, // i acute accent
C_oacute = 0x005f, // o acute accent
C_uacute = 0x0060, // u acute accent
C_ccedil = 0x007b, // c cedilla
C_division = 0x007c, // division sign
C_Ntilde = 0x007d, // N tilde
C_ntilde = 0x007e, // n tilde
C_block = 0x007f // solid block
};
int code, channel, character;
/* decode next pair of bytes from the odd or even field buffer */
if (!DecodeBits(fChannel == C_RADEON_CC1 || fChannel == C_RADEON_CC2 ? buffer0 : buffer1, code))
return false;
/* swap decoded bytes */
code = ((code << 8) & 0xff00) | ((code >> 8) & 0x00ff);
/* check parity */
for (int bit = 0; bit < 7; bit++) {
if ((code & (0x0001 << bit)) != 0)
code ^= 0x0080;
if ((code & (0x0100 << bit)) != 0)
code ^= 0x8000;
}
if ((code & 0x8080) != 0x8080) {
PRINT(("CCaption::Decode() - parity error (%04X)\n", code));
return false;
}
/* check channel number */
channel = (code & 0x0800) >> 12;
if (channel == 0) {
if (fChannel != C_RADEON_CC1 && fChannel != C_RADEON_CC3) {
PRINT(("CCaption::Decode() - ignore channel (%02X)\n", code & 0x7f7f));
return false;
}
}
else {
if (fChannel != C_RADEON_CC2 && fChannel != C_RADEON_CC4) {
PRINT(("CCaption::Decode() - ignore channel (%02X)\n", code & 0x7f7f));
return false;
}
}
if ((code & 0x7000) == 0x0000) {
/* one-byte standard character (0?XX) */
character = code & 0x007f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%04X>", code & 0x7f7f));
}
}
else if ((code & 0x7770) == 0x1120) {
/* middle row code (112X) */
fColor = code & 0x000f;
fText[fRow][fColumn] = (fColor << 8) + ' ';
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
switch (fColor & 0x000e) {
case C_WHITE:
PRINT(("<white"));
break;
case C_GREEN:
PRINT(("<green"));
break;
case C_BLUE:
PRINT(("<blue"));
break;
case C_CYAN:
PRINT(("<cyan"));
break;
case C_RED:
PRINT(("<red"));
break;
case C_YELLOW:
PRINT(("<yellow"));
break;
case C_MAGENTA:
PRINT(("<magenta"));
break;
case C_ITALICS:
PRINT(("<italics"));
break;
}
if ((fColor & 0x0001) != 0)
PRINT((",underline>"));
else
PRINT((">"));
}
else if ((code & 0x7770) == 0x1130) {
/* two-byte special character (113X) */
character = (code & 0x000f);
fText[fRow][fColumn] = (fColor << 8) + character + 0x0080;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
switch (character) {
case C_reg:
PRINT(("&reg;"));
break;
case C_deg:
PRINT(("&deg;"));
break;
case C_frac12:
PRINT(("&frac12;"));
break;
case C_iquest:
PRINT(("&iquest;"));
break;
case C_trademark:
PRINT(("&trademark;"));
break;
case C_cent:
PRINT(("&cent;"));
break;
case C_pound:
PRINT(("&pound;"));
break;
case C_music:
PRINT(("&music;"));
break;
case C_agrave:
PRINT(("&agrave;"));
break;
case C_tspace:
PRINT(("&tspace;"));
break;
case C_egrave:
PRINT(("&egrave;"));
break;
case C_acirc:
PRINT(("&acirc;"));
break;
case C_ecirc:
PRINT(("&ecirc;"));
break;
case C_icirc:
PRINT(("&icirc;"));
break;
case C_ocirc:
PRINT(("&ocirc;"));
break;
case C_ucirc:
PRINT(("&ucirc;"));
break;
default:
PRINT(("<special=%04X>", code & 0x7f7f));
break;
}
}
else if ((code & 0x7770) == 0x1420) {
if (code == fLastControlCode)
return false;
fLastControlCode = code;
/* miscellaneous control code (142X) */
switch (code & 0x000f) {
case C_RCL:
// resume caption loading
PRINT(("<rcl>"));
break;
case C_BS:
// backspace
PRINT(("<bs>"));
if (fColumn > 0)
fText[fRow][--fColumn] = 0x0000;
break;
case C_AOF:
// alarm off
PRINT(("<aof>"));
break;
case C_AON:
// alarm on
PRINT(("<aon>"));
break;
case C_DER:
// delete to end of row
PRINT(("<der>"));
for (int column = fColumn; column < C_RADEON_CC_COLUMNS; column++)
fText[fRow][column] = 0x0000;
break;
case C_RU2:
// rollup captions (2 rows)
PRINT(("<ru2>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 2; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 2; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_RU3:
// rollup captions (3 rows)
PRINT(("<ru3>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 3; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 3; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_RU4:
// rollup captions (4 rows)
PRINT(("<ru4>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 4; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 4; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_FON:
// flash on
PRINT(("<fon>"));
break;
case C_RDC:
// resume direct captioning
PRINT(("<rdc>"));
break;
case C_TR:
// text restart
PRINT(("<tr>"));
fRow = fColumn = 0;
break;
case C_RTD:
// resume text display
PRINT(("<rtd>"));
fRow = fColumn = 0;
break;
case C_EDM:
// erase displayed memory
PRINT(("<edm>\n"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fDisplayText[row][column] = 0x0000;
}
DisplayCaptions();
break;
case C_CR:
// carriage return
PRINT(("<cr>"));
/* has no effect in caption loading mode */
break;
case C_ENM:
// erase non-displayed memory
PRINT(("<enm>"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_EOC:
// end of caption
PRINT(("<eoc>\n"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
const int code = fText[row][column];
fText[row][column] = fDisplayText[row][column];
fDisplayText[row][column] = code;
}
}
DisplayCaptions();
break;
}
}
else if ((code & 0x7770) == 0x1720) {
/* tab offset (172X) */
const int offset = code & 0x000f;
if (offset >= 1 && offset <= 3) {
PRINT(("<tab%d>", offset));
if ((fColumn += offset) >= C_RADEON_CC_COLUMNS - 1)
fColumn = C_RADEON_CC_COLUMNS - 1;
}
else {
PRINT(("<tab=%04X>", code & 0x7f7f));
}
}
else if ((code & 0x7040) == 0x1040) {
/* preamble address code (1Y4X, 1Y6X) */
switch (code & 0x0720) {
case C_ROW_1:
PRINT(("\n<row1"));
fRow = 0;
break;
case C_ROW_2:
PRINT(("\n<row2"));
fRow = 1;
break;
case C_ROW_3:
PRINT(("\n<row3"));
fRow = 2;
break;
case C_ROW_4:
PRINT(("\n<row4"));
fRow = 3;
break;
case C_ROW_5:
PRINT(("\n<row5"));
fRow = 4;
break;
case C_ROW_6:
PRINT(("\n<row6"));
fRow = 5;
break;
case C_ROW_7:
PRINT(("\n<row7"));
fRow = 6;
break;
case C_ROW_8:
PRINT(("\n<row8"));
fRow = 7;
break;
case C_ROW_9:
PRINT(("\n<row9"));
fRow = 8;
break;
case C_ROW_10:
PRINT(("\n<row10"));
fRow = 9;
break;
case C_ROW_11:
PRINT(("\n<row11"));
fRow = 10;
break;
case C_ROW_12:
PRINT(("\n<row12"));
fRow = 11;
break;
case C_ROW_13:
PRINT(("\n<row13"));
fRow = 12;
break;
case C_ROW_14:
PRINT(("\n<row14"));
fRow = 13;
break;
case C_ROW_15:
PRINT(("\n<row15"));
fRow = 14;
break;
default:
PRINT(("\n<pac=%04X>", code & 0x7f7f));
return false;
}
if ((code & 0x0010) == 0x0000) {
/* change color */
fColor = (code & 0x000f);
fColumn = 0;
switch (fColor & 0x000e) {
case C_WHITE:
PRINT((",white"));
break;
case C_GREEN:
PRINT((",green"));
break;
case C_BLUE:
PRINT((",blue"));
break;
case C_CYAN:
PRINT((",cyan"));
break;
case C_RED:
PRINT((",red"));
break;
case C_YELLOW:
PRINT((",yellow"));
break;
case C_MAGENTA:
PRINT((",magenta"));
break;
case C_ITALICS:
PRINT((",italics"));
break;
}
if ((fColor & 0x0001) != 0)
PRINT((",underline>"));
else
PRINT((">"));
}
else {
/* indent, white */
fColor = C_WHITE | (code & 0x0001);
fColumn = (code & 0x000e) << 1;
PRINT((",col%d>", fColumn));
}
}
else {
/* two one-byte standard characters */
character = (code >> 8) & 0x7f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%02X>", character));
}
character = (code >> 0) & 0x7f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%02X>", character));
}
}
return true;
}
void CCaption::DisplayCaptions() const
{
printf("\x1b[H\x1b[J");
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
if (fDisplayText[row][column] == 0x0000) {
printf("\x1b[0;47;37m ");
continue;
}
const int code = (fDisplayText[row][column] >> 0) & 0xff;
const int color = (fDisplayText[row][column] >> 8) & 0xff;
switch (color & 0x000e) {
case 0x0000: // WHITE
printf("\x1b[0;%d;40;37m", (color & 1) << 2);
break;
case 0x0002: // GREEN
printf("\x1b[0;%d;40;32m", (color & 1) << 2);
break;
case 0x0004: // BLUE
printf("\x1b[0;%d;40;34m", (color & 1) << 2);
break;
case 0x0006: // CYAN
printf("\x1b[0;%d;40;35m", (color & 1) << 2);
break;
case 0x0008: // RED
printf("\x1b[0;%d;40;31m", (color & 1) << 2);
break;
case 0x000a: // YELLOW
printf("\x1b[0;%d;40;33m", (color & 1) << 2);
break;
case 0x000c: // MAGENTA
printf("\x1b[0;%d;40;36m", (color & 1) << 2);
break;
case 0x000e: // WHITE ITALICS
if ((color & 1) == 0)
printf("\x1b[1;40;37m");
else
printf("\x1b[1;4;40;37m");
break;
}
if (code >= 0x20 && code <= 0x7f) {
switch (code) {
case 0x002a:
// aacute
printf("\xc3\xa1");
break;
case 0x005c:
// eacute
printf("\xc3\xa9");
break;
case 0x005e:
// iacute
printf("\xc3\xad");
break;
case 0x005f:
// oacute
printf("\xc3\xb3");
break;
case 0x0060:
// uacute
printf("\xc3\xba");
break;
case 0x007b:
// ccedil
printf("\xc3\xa7");
break;
case 0x007c:
// division
printf("\xc3\xb7");
break;
case 0x007d:
// Ntilde
printf("\xc3\x91");
break;
case 0x007e:
// ntilde
printf("\xc3\xb1");
break;
case 0x007f:
// block
printf("\xc1\xbf");
break;
default:
// ASCII character
printf("%c", code);
break;
}
}
else {
switch (code) {
case 0x0080:
// reg
printf("\xc2\xae");
break;
case 0x0081:
// deg
printf("\xc2\xb0");
break;
case 0x0082:
// frac12
printf("\xc2\xbd");
break;
case 0x0083:
// iquest
printf("\xc2\xbf");
break;
case 0x0084:
// trademark
printf("\xe2\x84");
break;
case 0x0085:
// cent
printf("\xc2\xa2");
break;
case 0x0086:
// pound
printf("\xc2\xa3");
break;
case 0x0087:
// music
printf("\xc2\xa7");
break;
case 0x0088:
// agrave
printf("\xc3\xa0");
break;
case 0x0089:
// tspace
printf("\x1b[0;47;37m ");
break;
case 0x008a:
// egrave
printf("\xc3\xa8");
break;
case 0x008b:
// acirc
printf("\xc3\xa2");
break;
case 0x008c:
// ecirc
printf("\xc3\xaa");
break;
case 0x008d:
// icirc
printf("\xc3\xae");
break;
case 0x008e:
// ocirc
printf("\xc3\xb4");
break;
case 0x008f:
// ucirc
printf("\xc3\xbb");
break;
default:
// buggy code
printf("<%02X>", code);
break;
}
}
}
printf("\n");
}
printf("\x1b[0;30;47m");
}
@@ -0,0 +1,67 @@
/******************************************************************************
/
/ File: CC.h
/
/ Description: Closed caption module.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __CC_H__
#define __CC_H__
#include "Capture.h"
enum cc_mode {
C_RADEON_CC1 = 0,
C_RADEON_CC2 = 1,
C_RADEON_CC3 = 2,
C_RADEON_CC4 = 3
};
enum cc_window {
C_RADEON_CC_VBI_LINE_WIDTH = 2048,
C_RADEON_CC_BLANK_START = 4*112,
C_RADEON_CC_VBI_LINE_NUMBER = 19,
C_RADEON_CC_BIT_DURATION = 56,
C_RADEON_CC_BITS_PER_FIELD = 16,
C_RADEON_CC_LEVEL_THRESHOLD = 32,
C_RADEON_CC_LINE = 21,
C_RADEON_CC_CHANNELS = 4,
C_RADEON_CC_ROWS = 15,
C_RADEON_CC_COLUMNS = 32
};
class CCaption {
public:
CCaption(CCapture & capture);
~CCaption();
status_t InitCheck() const;
void SetMode(cc_mode mode);
bool Decode(const unsigned char * buffer0,
const unsigned char * buffer1);
private:
bool DecodeBits(const unsigned char * buffer, int & data);
void DisplayCaptions() const;
private:
CCapture & fCapture;
cc_mode fChannel;
int fRow;
int fColumn;
int fColor;
int fLastControlCode;
short fText[C_RADEON_CC_ROWS][C_RADEON_CC_COLUMNS];
short fDisplayText[C_RADEON_CC_ROWS][C_RADEON_CC_COLUMNS];
};
#endif
@@ -0,0 +1,346 @@
/******************************************************************************
/
/ File: Capture.cpp
/
/ Description: ATI Radeon Capture Unit interface.
/
/ Copyright 2001, Carlos Hasan
/
/ TK: something about synchronization: I removed all the FIFO wait
/ functions as they aren't thread-safe and AFAIK not needed as
/ only 2D/3D register accesses are buffered
/
*******************************************************************************/
#include <Debug.h>
#include "Capture.h"
CCapture::CCapture(CRadeon & radeon)
: fRadeon(radeon),
fMode(C_RADEON_CAPTURE_FIELD_SINGLE),
fFormat(C_RADEON_CAPTURE_CCIR656),
fOffset0(0),
fOffset1(0),
fVBIOffset0(0),
fVBIOffset1(0),
fSize(0),
fVBISize(0),
fPitch(0),
fClip(),
fVBIClip()
{
PRINT(("CCapture::CCapture()\n"));
}
CCapture::~CCapture()
{
PRINT(("CCapture::~CCapture()\n"));
}
status_t CCapture::InitCheck() const
{
return fRadeon.InitCheck();
}
void CCapture::SetBuffer(capture_stream_format format, capture_buffer_mode mode,
int offset0, int offset1, int size, int pitch)
{
PRINT(("CCapture::SetBuffer(%s, %s, 0x%08x, 0x%08x, 0x%08x, %d)\n",
"BROOKTREE\0CCIR656\0\0\0ZVIDEO\0\0\0\0VIP"+10*format,
"FIELD-SINGLE\0FIELD-DOUBLE\0BOB-SINGLE\0\0\0"
"BOB-DOUBLE\0\0\0WEAVE-SINGLE\0WEAVE-DOUBLE"+13*mode,
offset0, offset1, size, pitch));
fMode = mode;
fFormat = format;
fOffset0 = offset0 + fRadeon.VirtualMemoryBase();
fOffset1 = offset1 + fRadeon.VirtualMemoryBase();
fSize = size;
fPitch = pitch;
}
void CCapture::SetClip(int left, int top, int right, int bottom)
{
PRINT(("CCapture::SetClip(%d, %d, %d, %d)\n",
left, top, right, bottom));
fClip.SetTo(left, top, right, bottom);
}
void CCapture::SetVBIBuffer(int offset0, int offset1, int size)
{
PRINT(("CCapture::SetVBIBuffer(0x%08x, 0x%08x, %d)\n", offset0, offset1, size));
fVBIOffset0 = offset0 + fRadeon.VirtualMemoryBase();
fVBIOffset1 = offset1 + fRadeon.VirtualMemoryBase();
fVBISize = size;
}
void CCapture::SetVBIClip(int left, int top, int right, int bottom)
{
PRINT(("CCapture::SetVBIClip(%d, %d, %d, %d)\n",
left, top, right, bottom));
fVBIClip.SetTo(left, top, right, bottom);
}
void CCapture::Start(bool vbi)
{
PRINT(("CCapture::Start(%d)\n", vbi));
// initially the capture unit is disabled
//fRadeon.WaitForFifo(2);
SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
// select buffer offset and pitch
//fRadeon.WaitForFifo(5);
switch (fMode) {
case C_RADEON_CAPTURE_FIELD_SINGLE:
/* capture single field, single buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
break;
case C_RADEON_CAPTURE_FIELD_DOUBLE:
/* capture single field, double buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
break;
case C_RADEON_CAPTURE_BOB_SINGLE:
/* capture interlaced frame, single buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
break;
case C_RADEON_CAPTURE_BOB_DOUBLE:
/* capture interlaced frame, double buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + fSize);
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
break;
case C_RADEON_CAPTURE_WEAVE_SINGLE:
/* capture deinterlaced frame, single buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
break;
case C_RADEON_CAPTURE_WEAVE_DOUBLE:
/* capture deinterlaced frame, double buffer */
SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + (fPitch << 1));
SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
break;
}
// select VBI buffer offset
//fRadeon.WaitForFifo(4);
// FIXME: change according to the buffering mode?
SetRegister(C_RADEON_CAP0_VBI0_OFFSET, fVBIOffset0);
SetRegister(C_RADEON_CAP0_VBI1_OFFSET, fVBIOffset0 + fVBISize);
SetRegister(C_RADEON_CAP0_VBI2_OFFSET, fVBIOffset1);
SetRegister(C_RADEON_CAP0_VBI3_OFFSET, fVBIOffset1 + fVBISize);
// select capture clipping window
//fRadeon.WaitForFifo(2);
SetRegister(C_RADEON_CAP0_H_WINDOW,
((fClip.Left() << 1) & C_RADEON_CAP0_H_START) |
((fClip.Width() << 17) & C_RADEON_CAP0_H_WIDTH));
SetRegister(C_RADEON_CAP0_V_WINDOW,
((fClip.Top() << 0) & C_RADEON_CAP0_V_START) |
((fClip.Bottom() << 16) & C_RADEON_CAP0_V_END));
// select VBI clipping window
//fRadeon.WaitForFifo(2);
SetRegister(C_RADEON_CAP0_VBI_H_WINDOW,
((fVBIClip.Left() << 0) & C_RADEON_CAP0_VBI_H_START) |
((fVBIClip.Width() << 16) & C_RADEON_CAP0_VBI_H_WIDTH));
SetRegister(C_RADEON_CAP0_VBI_V_WINDOW,
((fVBIClip.Top() << 0) & C_RADEON_CAP0_VBI_V_START) |
((fVBIClip.Bottom() << 16) & C_RADEON_CAP0_VBI_V_END));
// select buffer type, input mode, video format and buffering mode
//fRadeon.WaitForFifo(10);
switch (fMode) {
case C_RADEON_CAPTURE_FIELD_SINGLE:
case C_RADEON_CAPTURE_FIELD_DOUBLE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FIELD);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
break;
case C_RADEON_CAPTURE_BOB_SINGLE:
case C_RADEON_CAPTURE_BOB_DOUBLE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_ALTERNATING);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
break;
case C_RADEON_CAPTURE_WEAVE_SINGLE:
case C_RADEON_CAPTURE_WEAVE_DOUBLE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FRAME);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FRAME);
break;
}
switch (fMode) {
case C_RADEON_CAPTURE_FIELD_SINGLE:
case C_RADEON_CAPTURE_BOB_SINGLE:
case C_RADEON_CAPTURE_WEAVE_SINGLE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_SINGLE);
break;
case C_RADEON_CAPTURE_FIELD_DOUBLE:
case C_RADEON_CAPTURE_BOB_DOUBLE:
case C_RADEON_CAPTURE_WEAVE_DOUBLE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_DOUBLE);
break;
}
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_INPUT_MODE, C_RADEON_CAP0_INPUT_MODE_CONTINUOUS);
SetRegister(C_RADEON_CAP0_CONFIG,
C_RADEON_CAP0_VIDEO_IN_FORMAT | C_RADEON_CAP0_VIDEO_SIGNED_UV, C_RADEON_CAP0_VIDEO_IN_VYUY422);
// select stream format and port mode
//fRadeon.WaitForFifo(4);
switch (fFormat) {
case C_RADEON_CAPTURE_BROOKTREE:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_BROOKTREE);
SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
break;
case C_RADEON_CAPTURE_CCIR656:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_CCIR656);
SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
break;
case C_RADEON_CAPTURE_ZOOMVIDEO:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_ZV);
SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
break;
case C_RADEON_CAPTURE_VIP:
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_VIP);
SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
break;
}
// set capture mirror mode, field sense, downscaler/decimator, enable 3:4 pull down
//fRadeon.WaitForFifo(16);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_MIRROR_EN, 0);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MIRROR_EN, 0);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_START_FIELD, C_RADEON_CAP0_START_ODD_FIELD);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HORZ_DOWN, C_RADEON_CAP0_HORZ_DOWN_1X);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VERT_DOWN, C_RADEON_CAP0_VERT_DOWN_1X);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_HORZ_DOWN, C_RADEON_CAP0_VBI_HORZ_DOWN_1X);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HDWNS_DEC, C_RADEON_CAP0_DECIMATOR);
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_SOFT_PULL_DOWN_EN, C_RADEON_CAP0_SOFT_PULL_DOWN_EN);
// prepare to enable capture
//fRadeon.WaitForFifo(14);
// disable test and debug modes
SetRegister(C_RADEON_TEST_DEBUG_CNTL, 0);
SetRegister(C_RADEON_CAP0_VIDEO_SYNC_TEST, 0);
SetRegister(C_RADEON_CAP0_DEBUG, C_RADEON_CAP0_V_SYNC);
// connect capture engine to AMC connector
SetRegister(C_RADEON_VIDEOMUX_CNTL, 1, 1);
// select capture engine clock source to PCLK
SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_PCLK);
// enable capture unit
SetRegister(C_RADEON_CAP0_TRIG_CNTL,
C_RADEON_CAP0_TRIGGER_W_CAPTURE | C_RADEON_CAP0_EN);
// enable VBI capture
SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_EN,
(vbi ? C_RADEON_CAP0_VBI_EN : 0));
}
void CCapture::Stop()
{
PRINT(("CCapture::Stop()\n"));
// disable capture unit
//fRadeon.WaitForFifo(4);
// disable capture unit
SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
// disable the capture engine clock (set to ground)
fRadeon.SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_GND);
}
void CCapture::SetInterrupts(bool enable)
{
PRINT(("CCapture::SetInterrupts(%d)\n", enable));
fRadeon.SetRegister(C_RADEON_CAP_INT_CNTL,
C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN,
(enable ? C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN : 0));
// clear any stick interrupt
fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
}
int CCapture::WaitInterrupts(int * sequence, bigtime_t * when, bigtime_t timeout)
{
int mask;
if (fRadeon.WaitInterrupt(&mask, sequence, when, timeout) == B_OK) {
/*
int mask = fRadeon.Register(C_RADEON_CAP_INT_STATUS);
fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
*/
return
((mask & C_RADEON_CAP0_BUF0_INT) != 0 ? C_RADEON_CAPTURE_BUF0_INT : 0) |
((mask & C_RADEON_CAP0_BUF1_INT) != 0 ? C_RADEON_CAPTURE_BUF1_INT : 0) |
((mask & C_RADEON_CAP0_BUF0_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF0_EVEN_INT : 0) |
((mask & C_RADEON_CAP0_BUF1_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF1_EVEN_INT : 0) |
((mask & C_RADEON_CAP0_VBI0_INT) != 0 ? C_RADEON_CAPTURE_VBI0_INT : 0) |
((mask & C_RADEON_CAP0_VBI1_INT) != 0 ? C_RADEON_CAPTURE_VBI1_INT : 0);
}
return 0;
}
int CCapture::Register(radeon_register index, int mask)
{
return fRadeon.Register(index, mask);
}
void CCapture::SetRegister(radeon_register index, int value)
{
fRadeon.SetRegister(index, value);
}
void CCapture::SetRegister(radeon_register index, int mask, int value)
{
fRadeon.SetRegister(index, mask, value);
}
@@ -0,0 +1,89 @@
/******************************************************************************
/
/ File: Capture.h
/
/ Description: ATI Radeon Capture Unit interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __CAPTURE_H__
#define __CAPTURE_H__
#include "Radeon.h"
enum capture_buffer_mode {
C_RADEON_CAPTURE_FIELD_SINGLE = 0,
C_RADEON_CAPTURE_FIELD_DOUBLE = 1,
C_RADEON_CAPTURE_BOB_SINGLE = 2,
C_RADEON_CAPTURE_BOB_DOUBLE = 3,
C_RADEON_CAPTURE_WEAVE_SINGLE = 4,
C_RADEON_CAPTURE_WEAVE_DOUBLE = 5
};
enum capture_stream_format {
C_RADEON_CAPTURE_BROOKTREE = 0,
C_RADEON_CAPTURE_CCIR656 = 1,
C_RADEON_CAPTURE_ZOOMVIDEO = 2,
C_RADEON_CAPTURE_VIP = 3
};
enum capture_interrupt_mask {
C_RADEON_CAPTURE_BUF0_INT = 1 << 0,
C_RADEON_CAPTURE_BUF0_EVEN_INT = 1 << 1,
C_RADEON_CAPTURE_BUF1_INT = 1 << 2,
C_RADEON_CAPTURE_BUF1_EVEN_INT = 1 << 3,
C_RADEON_CAPTURE_VBI0_INT = 1 << 4,
C_RADEON_CAPTURE_VBI1_INT = 1 << 5
};
class CCapture {
public:
CCapture(CRadeon & radeon);
~CCapture();
status_t InitCheck() const;
void SetBuffer(capture_stream_format format, capture_buffer_mode mode,
int offset0, int offset1, int size, int pitch);
void SetClip(int left, int top, int right, int bottom);
void SetVBIBuffer(int offset0, int offset1, int size);
void SetVBIClip(int left, int top, int right, int bottom);
void Start(bool vbi = false);
void Stop();
public:
void SetInterrupts(bool enable);
int WaitInterrupts(int * sequence, bigtime_t * when, bigtime_t timeout);
private:
int Register(radeon_register index, int mask);
void SetRegister(radeon_register index, int value);
void SetRegister(radeon_register index, int mask, int value);
private:
CRadeon & fRadeon;
capture_buffer_mode fMode;
capture_stream_format fFormat;
int fOffset0;
int fOffset1;
int fVBIOffset0;
int fVBIOffset1;
int fSize;
int fVBISize;
int fPitch;
CRadeonRect fClip;
CRadeonRect fVBIClip;
};
#endif
@@ -0,0 +1,234 @@
/******************************************************************************
/
/ File: I2C.cpp
/
/ Description: ATI Radeon I2C Serial Bus interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <Debug.h>
#include "I2CPort.h"
CI2CPort::CI2CPort(CRadeon & radeon, int rate)
: fRadeon(radeon),
fNfactor(0),
fMfactor(0),
fTimeLimit(0)
{
PRINT(("CI2CPort::CI2CPort()\n"));
if( fRadeon.InitCheck() == B_OK ) {
int refFreq, refDiv, minFreq, maxFreq, xclock;
fRadeon.GetPLLParameters(refFreq, refDiv, minFreq, maxFreq, xclock);
double n = (xclock * 10000.0) / (4.0 * rate);
for (fNfactor = 1; fNfactor < 255; fNfactor++) {
if (fNfactor * (fNfactor - 1) > n)
break;
}
fMfactor = fNfactor - 1;
fTimeLimit = 2 * fNfactor;
// enable I2C bus
fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, 0x00ff0000,
C_RADEON_I2C_SEL | C_RADEON_I2C_EN);
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0, 0x000000ff,
C_RADEON_I2C_DONE | C_RADEON_I2C_NACK |
C_RADEON_I2C_HALT | C_RADEON_I2C_SOFT_RST |
C_RADEON_I2C_DRIVE_EN | C_RADEON_I2C_DRIVE_SEL);
#if DEBUG
PRINT(("CI2CPort::CI2CPort() - I2C devices found at ports: "));
for (int address = 0x80; address <= 0xff; address += 0x02) {
if (Probe(address))
PRINT(("0x%02x ", address));
}
PRINT(("\n"));
#endif
}
}
CI2CPort::~CI2CPort()
{
PRINT(("CI2CPort::~CI2CPort()\n"));
if( fRadeon.InitCheck() == B_OK ) {
// disable I2C bus
fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, 0);
}
}
status_t CI2CPort::InitCheck() const
{
return fRadeon.InitCheck();
}
CRadeon & CI2CPort::Radeon() const
{
return fRadeon;
}
bool CI2CPort::Probe(int address)
{
char buffer[1];
return Read(address, buffer, sizeof(buffer));
}
bool CI2CPort::Write(int address, const char * buffer, int length)
{
if (Send(address, buffer, length, true, true) == length)
return true;
return false;
}
bool CI2CPort::Read(int address, char * buffer, int length)
{
if (Receive(address, buffer, length, true, true) == length)
return true;
return false;
}
bool CI2CPort::Write(int address, const char * buffer, int length, char * result, int reslen)
{
if (Send(address, buffer, length, true, false) == length)
if (Receive(address, result, reslen, true, true) == reslen)
return true;
return false;
}
int CI2CPort::Register(int address, int index)
{
char value = index;
if (Send(address, &value, sizeof(value), true, false) == sizeof(value)) {
if (Receive(address, &value, sizeof(value), true, true) == sizeof(value))
return value & 0xff;
}
PRINT(("CI2CPort::Register() - error\n"));
return -1;
}
void CI2CPort::SetRegister(int address, int index, int value)
{
char buffer[2];
buffer[0] = index;
buffer[1] = value;
if (Send(address, buffer, sizeof(buffer), true, true) != sizeof(buffer))
PRINT(("CI2CPort::SetRegister() - error\n"));
}
int CI2CPort::Send(int address, const char * buffer, int length, bool start, bool stop)
{
//fRadeon.WaitForFifo(4 + length);
// clear status bit
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
C_RADEON_I2C_DONE | C_RADEON_I2C_NACK |
C_RADEON_I2C_HALT | C_RADEON_I2C_SOFT_RST);
// write address
fRadeon.SetRegister(C_RADEON_I2C_DATA, address & 0xfffffffe);
// write data
for (int offset = 0; offset < length; offset++)
fRadeon.SetRegister(C_RADEON_I2C_DATA, buffer[offset]);
//
fRadeon.SetRegister(C_RADEON_I2C_CNTL_1,
(fTimeLimit << 24) | length |
C_RADEON_I2C_EN | C_RADEON_I2C_SEL | 0x100);
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
(fNfactor << 24) | (fMfactor << 16) |
C_RADEON_I2C_GO | C_RADEON_I2C_DRIVE_EN |
(start ? C_RADEON_I2C_START : 0) | (stop ? C_RADEON_I2C_STOP : 0));
for (int wait = 0; wait < 100; wait++) {
if ((fRadeon.Register(C_RADEON_I2C_CNTL_0) & C_RADEON_I2C_GO) == 0)
break;
}
if (WaitAck() != C_RADEON_I2C_DONE) {
Stop();
return 0;
}
return length;
}
int CI2CPort::Receive(int address, char * buffer, int length, bool start, bool stop)
{
//fRadeon.WaitForFifo(length + 4);
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
C_RADEON_I2C_DONE | C_RADEON_I2C_NACK |
C_RADEON_I2C_HALT | C_RADEON_I2C_SOFT_RST);
fRadeon.SetRegister(C_RADEON_I2C_DATA, address | 0x00000001);
fRadeon.SetRegister(C_RADEON_I2C_CNTL_1,
(fTimeLimit << 24) | C_RADEON_I2C_EN | //C_RADEON_I2C_SEL |
length | 0x100);
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
(fNfactor << 24) | (fMfactor << 16) | C_RADEON_I2C_GO |
(start ? C_RADEON_I2C_START : 0) | (stop ? C_RADEON_I2C_STOP : 0) |
C_RADEON_I2C_DRIVE_EN | C_RADEON_I2C_RECEIVE);
for (int wait = 0; wait < 100; wait++) {
if ((fRadeon.Register(C_RADEON_I2C_CNTL_0) & C_RADEON_I2C_GO) == 0)
break;
}
if (WaitAck() != C_RADEON_I2C_DONE)
return 0;
snooze(1000);
for (int offset = 0; offset < length; offset++) {
//fRadeon.WaitForFifo(1);
buffer[offset] = fRadeon.Register(C_RADEON_I2C_DATA) & 0xff;
}
return length;
}
int CI2CPort::WaitAck()
{
for (int wait = 0; wait < 100; wait++) {
int control = fRadeon.Register(C_RADEON_I2C_CNTL_0);
if ((control & C_RADEON_I2C_HALT) != 0)
return C_RADEON_I2C_HALT;
if ((control & C_RADEON_I2C_NACK) != 0)
return C_RADEON_I2C_NACK;
if ((control & C_RADEON_I2C_DONE) != 0)
return C_RADEON_I2C_DONE;
snooze(1000);
}
PRINT(("CI2CPort::WaitAck() - Time out!\n"));
return C_RADEON_I2C_HALT;
}
void CI2CPort::Stop()
{
// reset status flags
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
C_RADEON_I2C_DONE | C_RADEON_I2C_NACK | C_RADEON_I2C_HALT, 0);
// issue abort call
fRadeon.SetRegister(C_RADEON_I2C_CNTL_0,
C_RADEON_I2C_ABORT | C_RADEON_I2C_GO, C_RADEON_I2C_ABORT | C_RADEON_I2C_GO);
// wait GO bit to go low
for (int wait = 0; wait < 100; wait++) {
if ((fRadeon.Register(C_RADEON_I2C_CNTL_0) & C_RADEON_I2C_GO) == 0)
snooze(1000);
}
PRINT(("CI2CPort::Stop() - Time out!\n"));
}
@@ -0,0 +1,63 @@
/******************************************************************************
/
/ File: I2C.h
/
/ Description: ATI Radeon I2C Serial Bus interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __I2C_PORT_H__
#define __I2C_PORT_H__
#include "Radeon.h"
enum i2c_port_clock_rate {
C_RADEON_I2C_MIN_CLOCK_RATE = 7500,
C_RADEON_I2C_MAX_CLOCK_RATE = 100000,
C_RADEON_I2C_DEFAULT_CLOCK_RATE = 80000
};
class CI2CPort {
public:
CI2CPort(CRadeon & radeon, int rate = C_RADEON_I2C_DEFAULT_CLOCK_RATE);
~CI2CPort();
status_t InitCheck() const;
CRadeon & Radeon() const;
bool Probe(int address);
public:
bool Write(int address, const char * buffer, int length);
bool Read(int address, char * buffer, int length);
bool Write(int address, const char * buffer, int length, char * output, int outlen);
public:
int Register(int address, int index);
void SetRegister(int address, int index, int value);
private:
int Send(int address, const char * buffer, int length, bool start, bool stop);
int Receive(int address, char * buffer, int length, bool start, bool stop);
int WaitAck();
void Stop();
private:
CRadeon & fRadeon;
int fNfactor;
int fMfactor;
int fTimeLimit;
};
#endif
@@ -0,0 +1,878 @@
/******************************************************************************
/
/ File: MSP3430.cpp
/
/ Description: Micronas Multistandard Sound Processor (MSP) interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <Debug.h>
#include "MSP3430.h"
enum MSP3430_register {
MSP3430_CONTROL = 0x00, // R/W control register
MSP3430_WR_DEM = 0x10, // Write demodulator register
MSP3430_RD_DEM = 0x11, // Read demodulator register
MSP3430_WR_DSP = 0x12, // Read DSP register
MSP3430_RD_DSP = 0x13 // Write DSP register
};
enum MSP3430_control_register {
MSP3430_CONTROL_NORMAL = 0x0000, // normal operation mode
MSP3430_CONTROL_RESET = 0x8000 // reset mode
};
enum MSP3430_wr_dem_register {
MSP3430_DEM_STANDARD_SEL = 0x0020, // standard selection
MSP3430_DEM_MODUS = 0x0030, // demodulator options
MSP3430_DEM_I2S_CONFIG = 0x0040 // I2S configuration
};
enum MSP3430_rd_dem_register {
MSP3430_DEM_STANDARD_RES = 0x007e, // standard detection result
MSP3430_DEM_STATUS = 0x0200 // status register
};
enum MSP3430_wr_dsp_register {
// preprocessing
MSP3430_DSP_FM_PRESCALE = 0x000e, // FM/AM analog signal prescale
MSP3430_DSP_PRE_FM = BITS(15:8),
MSP3430_DSP_FM_MATRIX = BITS(7:0),
MSP3430_DSP_NICAM_PRESCALE = 0x0010, // NICAM digital signal prescale
MSP34300_DSP_PRE_NICAM = BITS(15:8),
MSP3430_DSP_PRE_I2S2 = 0x0012, // I2S digital signal prescale
MSP3430_DSP_PRE_I2S1 = 0x0016,
MSP3430_DSP_PRE_SCART = 0x000d, // SCART prescale
// source select and output channel matrix
MSP3430_DSP_SRC_MAT_MAIN = 0x0008, // loudspeaker source and matrix
MSP3430_DSP_SRC_MAIN = BITS(15:8),
MSP3430_DSP_MAT_MAIN = BITS(7:0),
MSP3430_DSP_SRC_MAT_AUX = 0x0009, // headphone source and matrix
MSP3430_DSP_SRC_AUX = BITS(15:8),
MSP3430_DSP_MAT_AUX = BITS(7:0),
MSP3430_DSP_SRC_MAT_SCART1 = 0x000a, // SCART1 source and matrix
MSP3430_DSP_SRC_SCART1 = BITS(15:8),
MSP3430_DSP_MAT_SCART1 = BITS(7:0),
MSP3430_DSP_SRC_MAT_SCART2 = 0x0041, // SCART2 source and matrix
MSP3430_DSP_SRC_SCART2 = BITS(15:8),
MSP3430_DSP_MAT_SCART2 = BITS(7:0),
MSP3430_DSP_SRC_MAT_I2S = 0x000b, // I2S source and matrix
MSP3430_DSP_SRC_I2S = BITS(15:8),
MSP3430_DSP_MAT_I2S = BITS(7:0),
MSP3430_DSP_SRC_MAT_QPEAK = 0x000c, // QuasiPeak detector source and matrix
MSP3430_DSP_SRC_QPEAK = BITS(15:8),
MSP3430_DSP_MAT_QPEAK = BITS(7:0),
// loudspeaker and headphone processing
MSP3430_DSP_VOL_MAIN = 0x0000, // loudspeaker volume
MSP3430_DSP_VOL_AUX = 0x0006, // headphone volume
MSP3430_DSP_AVC = 0x0029, // automatic volume correction
MSP3430_DSP_BAL_MAIN = 0x0001, // loudspeaker balance
MSP3430_DSP_BAL_AUX = 0x0030, // headphone balance
MSP3430_DSP_TONE_MODE = 0x0020, // select bass/treble or equalizer
MSP3430_DSP_BASS_MAIN = 0x0002, // loudspeaker bass
MSP3430_DSP_BASS_AUX = 0x0031, // headphone bass
MSP3430_DSP_TREB_MAIN = 0x0003, // loudspeaker treble
MSP3430_DSP_TREB_AUX = 0x0032, // headphone treble
MSP3430_DSP_EQUAL_BAND1 = 0x0021, // equalizer coefficients
MSP3430_DSP_EQUAL_BAND2 = 0x0022,
MSP3430_DSP_EQUAL_BAND3 = 0x0023,
MSP3430_DSP_EQUAL_BAND4 = 0x0024,
MSP3430_DSP_EQUAL_BAND5 = 0x0025,
MSP3430_DSP_LOUD_MAIN = 0x0004, // loudspeaker loudness
MSP3430_DSP_LOUD_AUX = 0x0033, // headphone loudness
MSP3430_DSP_SPAT_MAIN = 0x0005, // spatial effects
// subwoofer output channel
MSP3430_DSP_SUBW_LEVEL = 0x002c, // subwoofer level
MSP3430_DSP_SUBW_FREQ = 0x002d, // subwoofer frequency
// micronas dynamic bass
MSP3430_DSP_MDB_STR = 0x0068, // MDB strength
MSP3430_DSP_MDB_LIM = 0x0069, // MDB limit
MSP3430_DSP_MDB_HMC = 0x006a, // MDB harmonic content
MSP3430_DSP_MDB_LP = 0x006b, // MDB low frequency
MSP3430_DSP_MDB_HP = 0x006c, // MDB high frequency
// SCART output channel
MSP3430_DSP_VOL_SCART1 = 0x0007, // SCART1 volume
MSP3430_DSP_VOL_SCART2 = 0x0040, // SCART2 volume
// SCART switches and digital I/O pins
MSP3430_DSP_ACB_REG = 0x0013, // SCART switches
MSP3430_DSP_BEEPER = 0x0014 // Beeper volume and frequency
};
enum MSP3430_rd_dsp_register {
// quasi-peak detector readout
MSP3430_DSP_QPEAK_L = 0x0019, // Quasipeak detector left and right
MSP3430_DSP_QPEAK_R = 0x001a,
// MSP 34x0G version readout
MSP3430_DSP_MSP_HARD_REVISION = 0x001e, // MSP hardware and revision
MSP3430_DSP_MSP_HARD = BITS(15:8),
MSP3430_DSP_MSP_REVISION = BITS(7:0),
MSP3430_DSP_MSP_PRODUCT_ROM = 0x001f, // MSP product and ROM version
MSP3430_DSP_MSP_PRODUCT = BITS(15:8),
MSP3430_DSP_MSP_ROM = BITS(7:0)
};
enum MSP3430_sound_standard {
C_MSP3430_AUTOMATIC = 0x0001, // Automatic Detection (*)
C_MSP3430_M_FM_STEREO = 0x0002, // NTSC M/N (*)
C_MSP3430_BG_FM_STEREO = 0x0003, // PAL B/G (*)
C_MSP3430_DK1_FM_STEREO = 0x0004, // (*)
C_MSP3430_DK2_FM_STEREO = 0x0005, //
C_MSP3430_DK_FM_MONO = 0x0006, //
C_MSP3430_DK3_FM_STEREO = 0x0007, //
C_MSP3430_BG_NICAM_FM = 0x0008, // PAL B/G (*)
C_MSP3430_L_NICAM_AM = 0x0009, // (*)
C_MSP3430_I_NICAM_FM = 0x000A, // PAL I (*)
C_MSP3430_DK_NICAM_FM = 0x000B, // (*)
C_MSP3430_DK_NICAM_FM_HDEV2 = 0x000C,
C_MSP3430_DK_NICAM_FM_HDEV3 = 0x000D,
C_MSP3430_BTSC_STEREO = 0x0020, // BTSC Stereo (*)
C_MSP3430_BTSC_MONO_SAP = 0x0021,
C_MSP3430_M_JAPAN_STEREO = 0x0030, // NTSC Japan (*)
C_MSP3430_FM_RADIO = 0x0040, // FM Radio (*)
C_MSP3430_SAT_MONO = 0x0050, // Satellite Mono
C_MSP3430_SAT_STEREO = 0x0051, // Satellite Stereo
C_MSP3430_SAT_ASTRA_RADIO = 0x0060 // Astra Digital Radio
};
enum MSP3430_channel_source {
C_MSP3430_SOURCE_FM = 0x00, // FM/AM Mono
C_MSP3430_SOURCE_STEREO = 0x01, // Stereo or A/B (NICAM)
C_MSP3430_SOURCE_SCART = 0x02, // SCART Input
C_MSP3430_SOURCE_LANG_A = 0x03, // Stereo/Language A
C_MSP3430_SOURCE_LANG_B = 0x04, // Stereo/Language B
C_MSP3430_SOURCE_I2S1 = 0x05, // I2S1 Input
C_MSP3430_SOURCE_I2S2 = 0x06 // I2S2 Input
};
enum MSP3430_channel_matrix {
C_MSP3430_MATRIX_SOUND_A = 0x00, // Sound A Mono
C_MSP3430_MATRIX_SOUND_B = 0x10, // Sound B Mono
C_MSP3430_MATRIX_STEREO = 0x20, // Stereo
C_MSP3430_MATRIX_MONO = 0x30 // Mono
};
/*
-------------------------------------------------------------------
System Sound Sound Color
Carrier (MHz) Modulation System
-------------------------------------------------------------------
Satellite 6.5/5.85 FM-Mono/NICAM PAL
6.5 FM-Mono
7.02/7.2 FM-Stereo PAL
7.38/7.56 ASTRA Digital Radio
etc.
4.5/4.724212 FM-Stereo (A2) NTSC
-------------------------------------------------------------------
NTSC M/N 4.5 FM-FM (EIA-J) NTSC
-------------------------------------------------------------------
4.5 BTSC Stereo + SAP NTSC, PAL
FM-Radio 10.7 FM-Stereo Radio .
-------------------------------------------------------------------
*/
CMSP3430::CMSP3430(CI2CPort & port)
: fPort(port),
fAddress(0)
{
PRINT(("CMSP3430::CMSP3430()\n"));
if( fPort.InitCheck() == B_OK ) {
for (fAddress = 0x80; fAddress <= 0x80; fAddress += 0x02) {
if (fPort.Probe(fAddress)) {
PRINT(("CMSP3430::CMSP3430() - Sound Processor found at I2C port 0x%02x\n", fAddress));
break;
}
}
}
if( InitCheck() != B_OK )
PRINT(("CMSP3430::CMSP3430() - Sound processor not found!\n"));
}
CMSP3430::~CMSP3430()
{
PRINT(("CMSP3430::~CMSP3430()\n"));
}
status_t CMSP3430::InitCheck() const
{
status_t res;
res = fPort.InitCheck();
if( res != B_OK )
return res;
return (fAddress >= 0x80 && fAddress <= 0x80) ? B_OK : B_ERROR;
}
void CMSP3430::SetEnable(bool enable)
{
PRINT(("CMSP3430::SetEnable(%d)\n", enable));
SetControlRegister(MSP3430_CONTROL_RESET);
SetControlRegister(MSP3430_CONTROL_NORMAL);
if (enable) {
SetRegister(MSP3430_WR_DEM, MSP3430_DEM_MODUS, 0x2003);
SetRegister(MSP3430_WR_DEM, MSP3430_DEM_STANDARD_SEL, C_MSP3430_BTSC_STEREO); // 0x20
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_FM_PRESCALE, 0x2403);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, 0x0320);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, 0x7300);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, 0x0320);
}
else {
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, 0x0000);
}
}
#if 0
#pragma mark -
void CMSP3430::SetI2S(bool fast)
{
// select 2 x 16 bit (1024 MHz) or 2 x 32 bit (2048) frequency
SetRegister(MSP3430_WR_DEM, I2S_CONFIG, fast ? 0x0001 : 0x0000);
}
bool CMSP3430::IsSAP()
{
// bilingual sound mode or SAP present?
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0100) != 0x0000)
return true;
return false;
}
bool CMSP3430::IsMonoNICAM()
{
// independent mono sound (only NICAM)?
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0080) != 0x0000)
return true;
return false;
}
bool CMSP3430::IsStereo()
{
// mono/stereo indication
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0040) != 0x0000)
return true;
return false;
}
bool CMSP3430::IsFM()
{
// is analog sound standard (FM or AM) active?
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0120) == 0x0000)
return true;
return false;
}
bool CMSP3430::IsNICAM()
{
// digital sound (NICAM) available?
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0100) == 0x0100)
return true;
return false;
}
bool CMSP3430::HasSecondaryCarrier()
{
// detected secondary carrier (2nd A2 or SAP sub-carrier)
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0004) != 0x0000)
return true;
return false;
}
bool CMSP3430::HasPrimaryCarrier()
{
// detected primary carrier (Mono or MPX carrier)
if ((Register(MSP3430_RD_DEM, STATUS) & 0x0002) != 0x0000)
return true;
return false;
}
void CMSP3430::SetStandard(MSP3430_standard standard)
{
fStandard = standard;
// set sound mode, FM/AM matrix, source channels
switch (standard) {
C_MSP3430_STANDARD_BG_FM:
C_MSP3430_STANDARD_DK_FM:
// Sound Mode FM Matrix FM/AM Source Stereo A/B Source
// ---------------------------------------------------------------
// Mono Sound A Mono Mono Mono
C_MSP3430_STANDARD_M_KOREA:
C_MSP3430_STANDARD_M_JAPAN:
// Stereo Korean Stereo Stereo Stereo
// Stereo German Stereo Stereo Stereo
// Lang A & B No Matrix Left=A, Right=B Left=A, Right=B
C_MSP3430_STANDARD_BG_NICAM:
}
SetDemodulator();
}
void CMSP3430::SetFMPrescale(int gain, MSP3430_fm_matrix matrix, bool mute)
{
// set FM/AM prescale and FM matrix mode
fFMPrescale = (mute ? 0x00 : Clamp(gain, 0x00, 0x7f)) << 8;
/// see table 6--17, Appendix B.
switch (matrix) {
case C_MSP3430_MATRIX_NONE:
fFMPrescale |= 0x0000;
break;
case C_MSP3430_MATRIX_GERMAN_STEREO_BG:
fFMPrescale |= 0x0001;
break;
case C_MSP3430_MATRIX_KOREAN_STEREO:
fFMPrescale |= 0x0002;
break;
case C_MSP3430_MATRIX_SOUND_A_MONO:
fFMPrescale |= 0x0003;
break;
case C_MSP3430_MATROX_SOUND_B_MONO:
fFMPrescale |= 0x0004;
break;
}
SetDemodulator();
}
void CMSP3430::SetNICAMPrescale(int gain, bool mute)
{
// set NICAM prescale to 0..12 dB
fNICAMPrescale = (mute ? 0x00 : Clamp(0x20 + (0x5f * gain) / 12, 0x20, 0x7f)) << 8;
SetDemodulator();
}
void CMSP3430::SetI2SPrescale(int gain, bool mute)
{
// set digital I2S input prescale 0..18 dB
fI2SPrescale = (mute ? 0x00 : Clamp(0x10 + (0x7f * gain) / 18, 0x10, 0x7f) << 8;
SetSCARTInput();
}
void CMSP3430::SetSCARTPrescale(int gain, bool mute)
{
// set SCART input signal prescale 0..14 dB
fSCARTPrescale = (mute ? 0x00 : Clamp(0x19 + (0x66 * gain) / 14, 0x19, 0x7f) << 8;
SetSCARTInput();
}
void CMSP3430::SetSource(MSP3430_source_channel speaker,
MSP3430_source_channel headphone,
MSP3430_source_channel scart1,
MSP3430_source_channel scart2,
MSP3430_source_channel i2s,
MSP3430_source_channel qpeak)
{
// set source and matrix..
// select FM/AM, Stereo A/B, Stereo A, Stereo B, SCART, I2S1 or I2S2 source channels
// and select Sound A Mono, Sound B Mono, Stereo or Mono mode
fSrcMain = loudspeaker;
fSrcAux = headphone;
fSrcSCART1 = scart1;
fSrcSCART2 = scart2;
fSrcI2S = i2s;
fSrcQPeak = qpeak;
SetOutputChannels();
}
void CMSP3430::SetVolume(int level, bool mute, MSP3430_clipping_mode mode,
MSP3430_automatic_volume automatic)
{
// set volume between -114 dB and 12 dB with 1 dB step size
fVolume = (mute ? 0x00 : Clamp(level + 0x73, 0x01, 0x7f)) << 8;
switch (mode) {
case C_MSP3430_CLIP_REDUCE_VOLUME:
fVolume |= 0x00;
break;
case C_MSP3430_CLIP_REDUCE_TONE:
fVolume |= 0x01;
break;
case C_MSP3430_CLIP_COMPROMISE:
fVolume |= 0x02;
break;
case C_MSP3430_CLIP_DYNAMIC:
fVolume |= 0x03;
break;
}
// enable/disable automatic volume correction
switch (automatic) {
case C_MSP3430_AUTOMATIC_VOLUME_OFF:
fAVC = 0x0000;
break;
case C_MSP3430_AUTOMATIC_VOLUME_20_MS:
fAVC = 0x8100;
break;
case C_MSP3430_AUTOMATIC_VOLUME_2_SEC:
fAVC = 0x8200;
break;
case C_MSP3430_AUTOMATIC_VOLUME_4_SEC:
fAVC = 0x8400;
break;
case C_MSP3430_AUTOMATIC_VOLUME_8_SEC:
fAVC = 0x8800;
break;
}
SetOutputChannels();
}
void CMSP3430::SetBalance(int balance, MSP3430_balance_mode mode)
{
switch (mode) {
case C_MSP3430_BALANCE_LINEAR:
// set balance between -100% (right) and 100% (left)
fBalance = (((0x7f * Clamp(balance, -100, 100)) / 100) << 8) + 0x0000;
break;
case C_MSP3430_BALANCE_LOGARITHMIC:
// set balance between -128 dB (right) and 127 dB (left)
fBalance = (((0x7f * Clamp(balance, -128, 127)) / 127) << 8) + 0x0001;
break;
}
SetOutputChannels();
}
void CMSP3430::SetEqualizer(int bass, int treble)
{
// set bass to -12..12 dB or 14..20 dB
if (bass <= 12)
fBass = Clamp(0x00 + 8 * bass, -0x60, 0x60) << 8;
else
fBass = Clamp(0x68 + 4 * (bass - 14), 0x68, 0x7f) << 8;
// set treble to -12..15 dB
fTreble = Clamp(0x00 + 8 * treble, -0x60, 0x78) << 8;
// enable bass/treble and disable equalizer
fToneControl = 0x00;
fEqualizer[0] = fEqualizer[1] = fEqualizer[2] =
fEqualizer[3] = fEqualizer[4] = fEqualizer[5] = 0x00;
SetOutputChannels();
}
void CMSP3430::SetEqualizer(int gain[5])
{
// set five band equalizer (120 Hz, 500 Hz, 1500 Hz, 5000 Hz, 10000 Hz)
for (int index = 0; index < 5; index++)
fEqualizer[index] = Clamp(0x00 + 8 * gain[index], -0x60, 0x60) << 8;
// disable bass/treble and enable equalizer
fToneControl = 0xff;
fBass = fTreble = 0x00;
SetOutputChannels();
}
void CMSP3430::SetLoudness(int loudness, MSP3430_loudness_mode mode)
{
// set loudness gain between 0 dB and 17 dB
fLoudness = Clamp(0x00 + 4 * loudness, 0x00, 0x44) << 8;
switch (mode) {
case C_MSP3430_LOUDNESS_NORMAL:
fLoudness |= 0x0000;
break;
case C_MSP3430_LOUDNESS_SUPER_BASS:
fLoudness |= 0x0004;
break;
}
SetOutputChannels();
}
void CMSP3430::SetSpatial(int strength, MSP3430_spatial_mode mode, MSP3430_spatial_highpass pass)
{
// enlarge or reduce spatial effects -100% to +100%
fSpatial = Clamp(0x00 + (0x7f * strength) / 100, -0x80, 0x7f) << 8;
switch (mode) {
case C_MSP3430_SPATIAL_MODE_A:
fSpatial |= 0x0000;
break;
case C_MSP3430_SPATIAL_MODE_B:
fSpatial |= 0x0020;
break;
}
switch (pass) {
case C_MSP3430_SPATIAL_MAX_HIGH_PASS:
fSpatial |= 0x0000;
break;
case C_MSP3430_SPATIAL_2_3_HIGH_PASS:
fSpatial |= 0x0002;
break;
case C_MSP3430_SPATIAL_1_3_HIGH_PASS:
fSpatial |= 0x0004;
break;
case C_MSP3430_SPATIAL_MIN_HIGH_PASS:
fSpatial |= 0x0006;
break;
case C_MSP3430_SPATIAL_AUTO_HIGH_PASS:
fSpatial |= 0x0008;
break;
}
SetOutputChannels();
}
void CMSP3430::SetSubwoofer(int level, int frequency, bool mute, MSP3430_subwoofer_mode mode)
{
// set subwoofer level between -128 dB and 12 dB
fSubwooferLevel = (mute ? 0x80 : Clamp(0x00 + level, -128, 12)) << 8;
// set subwoofer corner frequency between 50..400 Hz
fSubwooferFrequency = Clamp(frequency / 10, 5, 40) << 8;
switch (mode) {
case C_MSP3430_SUBWOOFER_UNFILTERED:
fSubwooferFrequency |= 0x0000;
break;
case C_MSP3430_SUBWOOFER_HIGH_PASS:
fSubwooferFrequency |= 0x0001;
break;
case C_MSP3430_SUBWOOFER_MDB_MAIN:
fSubwooferFrequency |= 0x0002;
break;
}
// disable MDB?
fMDBStrength = 0x0000;
fMDBLimit = 0x0000;
fMDBHarmonic = 0x0000;
fMDBHighPass = 0x0a00;
fMDBLowPass = 0x0a00;
SetSubwooferAndMDBOutputChannels();
}
void CMSP3430::SetMDB(int strength, int limit, int harmonic,
int minfrequency, int maxfrequency, bool mute)
{
// set MDB effect strength 0..127
fMDBStrength = (mute ? 0x00 : Clamp(strength, 0x00, 0x7f)) << 7;
// set MDB amplitude limit between -32..0 dBFS
fMDBLimit = Clamp(limit, -32, 0) << 8;
// set MDB harmonic content 0..100%
fMDBHarmonic = Clamp((0x7f * harmonic) / 100, 0x00, 0x7f) << 8;
// set MDB low pass corner frequency 50..300 Hz
fMDBLowPass = Clamp(minFrequency / 10, 5, 30) << 8;
// set MDB high pass corner frequency 20..300 Hz
fMDBHighPass = Clamp(maxFrequency / 10, 2, 30) << 8;
// disable subwoofer level adjustments
fSubwooferLevel = 0x0000;
fSubwooferFrequency = 0x0002;
// for MDB, use dynamic clipping mode
fVolume = (fVolume & ~0x000f) | 0x0003;
SetSubwooferAndMDBOutputChannels();
}
void CMSP3430::SetSCART(int level1, int level2, bool mute,
MSP3430_scart_input input,
MSP3430_scart_output output1,
MSP3430_scart_output output2)
{
// set volume SCART1/2 output channel -114..12 dB
fSCART1Volume = (mute ? 0x00 : Clamp(0x73 + (0x7f * level1) / 12, 0x00, 0x7f)) << 8;
fSCART2Volume = (mute ? 0x00 : Clamp(0x73 + (0x7f * level2) / 12, 0x00, 0x7f)) << 8;
fSCART1Volume |= 0x0001;
fSCART2Volume |= 0x0001;
// SCART DSP input select
fACB = 0x0000;
switch (input) {
case C_MSP3430_SCART_INPUT_SCART1:
fACB = 0x0000;
break;
case C_MSP3430_SCART_INPUT_MONO:
fACB = 0x0100;
break;
case C_MSP3430_SCART_INPUT_SCART2:
fACB = 0x0200;
break;
case C_MSP3430_SCART_INPUT_SCART3:
fACB = 0x0300;
break;
case C_MSP3430_SCART_INPUT_SCART4:
fACB = 0x0020;
break;
case C_MSP3430_SCART_INPUT_MUTE:
fACB = 0x0320;
break;
}
// SCART1 output select
switch (output1) {
case C_MSP3430_SCART_OUTPUT_SCART3:
fACB |= 0x0000;
break;
case C_MSP3430_SCART_OUTPUT_SCART2:
fACB |= 0x0400;
break;
case C_MSP3430_SCART_OUTPUT_MONO:
fACB |= 0x0800;
break;
case C_MSP3430_SCART_OUTPUT_SCART1_DA:
fACB |= 0x0c00;
break;
case C_MSP3430_SCART_OUTPUT_SCART2_DA:
fACB |= 0x0080;
break;
case C_MSP3430_SCART_OUTPUT_SCART1_INPUT:
fACB |= 0x0480;
break;
case C_MSP3430_SCART_OUTPUT_SCART4_INPUT:
fACB |= 0x0880;
break;
case C_MSP3430_SCART_OUTPUT_MUTE:
fACB |= 0x0c80;
break;
}
// SCART2 output select
switch (output2) {
case C_MSP3430_SCART_OUTPUT_SCART3:
fACB |= 0x0000;
break;
case C_MSP3430_SCART_OUTPUT_SCART2:
fACB |= 0x1000;
break;
case C_MSP3430_SCART_OUTPUT_MONO:
fACB |= 0x2000;
break;
case C_MSP3430_SCART_OUTPUT_SCART1_DA:
fACB |= 0x3000;
break;
case C_MSP3430_SCART_OUTPUT_SCART2_DA:
fACB |= 0x0200;
break;
case C_MSP3430_SCART_OUTPUT_SCART1_INPUT:
fACB |= 0x1200;
break;
case C_MSP3430_SCART_OUTPUT_SCART4_INPUT:
fACB |= 0x2200;
break;
case C_MSP3430_SCART_OUTPUT_MUTE:
fACB |= 0x3200;
break;
}
SetSCARTSignalPath();
SetOutputChannels();
}
void CMSP3430::SetBeeper(int volume, MSP3430_beeper_frequency frequency, bool mute)
{
// set beeper volume 0..127
int beeper = (mute ? 0x00 : Clamp(volume, 0x00, 0x7f)) << 8;
// set beeper frequency 16, 1000 or 4000 Hz
switch (frequency) {
case C_MSP3430_BEEPER_16_HZ:
beeper |= 0x0001;
break;
case C_MSP3430_BEEPER_1_KHZ:
beeper |= 0x0040;
break;
case C_MSP3430_BEEPER_4_KHZ:
beeper |= 0x00ff;
break;
}
SetRegister(MSP3430_WR_DSP, BEEPER, beeper);
}
void CMSP3430::SetQuasiPeak(int left, int right)
{
// set quasipeak detector readout -32768..32767
fQPeakLeft = left;
fQPeakRight = right;
SetOutputChannels();
}
void CMSP3430::GetVersion(char * version)
{
int revision = Register(MSP3430_RD_DSP, MSP_HARD_REVISION);
int product = Register(MSP3430_RD_DSP, MSP_PRODUCT_ROM);
sprintf(version, "MSP34%02d%c-%c%d",
((product & MSP_PRODUCT) >> 8),
((revision & MSP_REVISION) >> 0) + 0x40,
((revision & MSP_HARD) >> 8) + 0x40,
((product & MSP_ROM) >> 0));
}
#pragma mark -
void CMSP3430::Reset()
{
// software reset
SetControlRegister(MSP3430_CONTROL_RESET);
SetControlRegister(MSP3430_CONTROL_NORMAL);
}
void CMSP3430::SetSCARTSignalPath()
{
// select SCART DSP input and output
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_ACB_REG,fACB);
}
void CMSP3430::SetDemodulator()
{
// set preferred mode and sound IF input
// (automatic, enable STATUS change, detect 4.5 MHz carrier as BTSC)
SetRegister(MSP3430_WR_DEM, MODUS, 0x2003);
// set preferred prescale (FM and NICAM)
SetRegister(MSP3430_WR_DSP, PRE_FM, fFMPrescale);
SetRegister(MSP3430_WR_DSP, PRE_NICAM, fNICAMPrescale);
// automatic sound standard selection
SetRegister(MSP3430_WR_DEM, MSP3430_DEM_STANDARD_SEL, 0x0001);
// readback the detected TV sound or FM-radio standard
while ((fStandard = Register(MSP3430_RD_DEM, STANDARD_RES)) >= 0x0800)
snooze(100000);
}
void CMSP3430::SetSCARTInput()
{
// select preferred prescale for SCART and I2C
SetRegister(MSP3430_WR_DSP, PRE_SCART, fSCARTPrescale);
SetRegister(MSP3430_WR_DSP, PRE_I2S1, fI2SPrescale);
SetRegister(MSP3430_WR_DSP, PRE_I2S2, fI2SPrescale);
}
void CMSP3430::SetOutputChannels()
{
// select source channel and matrix for each output
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, fMainMatrix);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_AUX, fAuxMatrix);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_SCART1, fSCART1Matrix);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_SCART2, fSCART2Matrix);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_I2S, fI2SMatrix);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_QPEAK, fQPeakMatrix);
// set audio baseband processing
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TONE_MODE, fToneControl);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BASS_MAIN, fBass);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BASS_AUX, fBass);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TREB_MAIN, fTreble);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TREB_AUX, fTreble);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND1, fEqualizer[0]);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND2, fEqualizer[1]);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND3, fEqualizer[2]);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND4, fEqualizer[3]);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND5, fEqualizer[4]);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_LOUD_MAIN, fLoudness);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_LOUD_AUX, fLoudness);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SPAT_MAIN, fSpatial);
// select volume for each output channel
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, fVolume);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_AUX, fVolume);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_AVC, fAVC);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BAL_MAIN, fBalance);
SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BAL_AUX, fBalance);
SetRegister(MSP3430_WR_DSP, VOL_SCART1, fSCART1Volume);
SetRegister(MSP3430_WR_DSP, VOL_SCART2, fSCART2Volume);
// set quasipeak detector readout
SetRegister(MSP3430_WR_DSP, QPEAK_L, fQPeakLeft);
SetRegister(MSP3430_WR_DSP, QPEAK_R, fQPeakRight);
}
void CMSP3430::SetSubwooferAndMDBOutputChannels()
{
// set subwoofer output channel
SetRegister(MSP3430_WR_DSP, SUBW_LEVEL, fSubwooferLevel);
SetRegister(MSP3430_WR_DSP, SUBW_FREQ, fSubwooferFrequency);
// set MDB control
SetRegister(MSP3430_WR_DSP, MDB_STR, fMDBStrength);
SetRegister(MSP3430_WR_DSP, MDB_LIM, fMDBLimit);
SetRegister(MSP3430_WR_DSP, MDB_HMC, fMDBHarmonic);
SetRegister(MSP3430_WR_DSP, MDB_LP, fMDBLowPass);
SetRegister(MSP3430_WR_DSP, MDB_HP, fMDBHighPass);
}
#pragma mark -
#endif
int CMSP3430::ControlRegister()
{
char message[1], result[2];
message[0] = MSP3430_CONTROL;
if (fPort.Write(fAddress, message, sizeof(message), result, sizeof(result)))
return ((result[0] << 8) & 0xff00) + ((result[1] << 0) & 0x00ff);
return 0;
}
void CMSP3430::SetControlRegister(int value)
{
char message[3];
message[0] = MSP3430_CONTROL;
message[1] = value >> 8;
message[2] = value >> 0;
if (!fPort.Write(fAddress, message, sizeof(message)))
PRINT(("CMSP3430::SetControl() - error\n"));
}
int CMSP3430::Register(int address, int subaddress)
{
char message[3], response[2];
message[0] = address;
message[1] = subaddress >> 8;
message[2] = subaddress >> 0;
if (fPort.Write(fAddress, message, sizeof(message), response, sizeof(response)))
return ((response[0] << 8) & 0xff00) + ((response[1] << 0) & 0x00ff);
return 0;
}
void CMSP3430::SetRegister(int address, int subaddress, int value)
{
char message[5];
message[0] = address;
message[1] = subaddress >> 8;
message[2] = subaddress >> 0;
message[3] = value >> 8;
message[4] = value >> 0;
if (!fPort.Write(fAddress, message, sizeof(message)))
PRINT(("CMSP3430::SetRegister() - error\n"));
}
@@ -0,0 +1,40 @@
/******************************************************************************
/
/ File: MSP3430.h
/
/ Description: Micronas Multistandard Sound Processor (MSP) interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __MSP3430_H__
#define __MSP3430_H__
#include "I2CPort.h"
class CMSP3430 {
public:
CMSP3430(CI2CPort & port);
~CMSP3430();
status_t InitCheck() const;
void SetEnable(bool enable);
private:
int ControlRegister();
void SetControlRegister(int value);
int Register(int address, int subaddress);
void SetRegister(int address, int subaddress, int value);
private:
CI2CPort & fPort;
int fAddress;
};
#endif
@@ -0,0 +1,899 @@
/******************************************************************************
/
/ File: Radeon.cpp
/
/ Description: ATI Radeon Graphics Chip interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <unistd.h>
#include <dirent.h>
#include <Debug.h>
#include <string.h>
//#include "Driver.h"
#include "Radeon.h"
static const char * const C_RADEON_REGISTER_AREA_NAME = "RadeonRegisters";
static const char * const C_RADEON_MEMORY_AREA_NAME = "RadeonMemory";
static const char * const C_RADEON_ROM_AREA_NAME = "RadeonROM";
// CRadeonRect
CRadeonRect::CRadeonRect()
: fLeft(0),
fTop(0),
fRight(0),
fBottom(0)
{
}
CRadeonRect::CRadeonRect(int left, int top, int right, int bottom)
: fLeft(left),
fTop(top),
fRight(right),
fBottom(bottom)
{
}
int CRadeonRect::Left() const
{
return fLeft;
}
int CRadeonRect::Top() const
{
return fTop;
}
int CRadeonRect::Right() const
{
return fRight;
}
int CRadeonRect::Bottom() const
{
return fBottom;
}
int CRadeonRect::Width() const
{
return fRight - fLeft + 1;
}
int CRadeonRect::Height() const
{
return fBottom - fTop + 1;
}
void CRadeonRect::SetLeft(int value)
{
fLeft = value;
}
void CRadeonRect::SetTop(int value)
{
fTop = value;
}
void CRadeonRect::SetRight(int value)
{
fRight = value;
}
void CRadeonRect::SetBottom(int value)
{
fBottom = value;
}
void CRadeonRect::SetTo(int left, int top, int right, int bottom)
{
fLeft = left;
fTop = top;
fRight = right;
fBottom = bottom;
}
void CRadeonRect::MoveTo(int left, int top)
{
fRight += left - fLeft;
fBottom += top - fTop;
fLeft += left - fLeft;
fTop += top - fTop;
}
void CRadeonRect::ResizeTo(int width, int height)
{
fRight = fLeft + width - 1;
fBottom = fTop + height - 1;
}
// CRadeon
CRadeon::CRadeon( const char *dev_name )
: fHandle(0),
fRegister(NULL),
fROM(NULL),
fVirtualCard(NULL),
fSharedInfo(NULL),
fRegisterArea(0),
fROMArea(0),
fVirtualCardArea(0),
fSharedInfoArea(0)
{
PRINT(("CRadeon::CRadeon()\n"));
if ((fHandle = open(dev_name, O_RDWR | O_CLOEXEC)) < 0) {
PRINT(("CRadeon::CRadeon() - Can't open kernel driver\n"));
return;
}
radeon_get_private_data gpd;
if (GetDeviceInformation(gpd) < B_OK) {
PRINT(("CRadeon::CRadeon() - Can't get device information\n"));
return;
}
CloneArea(
"Radeon virtual card", gpd.virtual_card_area,
&fVirtualCardArea, (void **)&fVirtualCard );
CloneArea(
"Radeon shared info", gpd.shared_info_area,
&fSharedInfoArea, (void **)&fSharedInfo );
if( fSharedInfo != NULL ) {
CloneArea(
"Radeon regs", fSharedInfo->regs_area,
&fRegisterArea, (void **)&fRegister );
CloneArea(
"Radeon ROM", fSharedInfo->ROM_area,
&fROMArea, (void **)&fROM );
}
if (fVirtualCard == NULL || fSharedInfo == NULL ||
fROM == NULL || fRegister == NULL)
{
PRINT(("CRadeon::CRadeon() - Can't map memory apertures\n"));
return;
}
PRINT(("CRadeon::CRadeon() - ATI Radeon found\n"));
}
CRadeon::~CRadeon()
{
PRINT(("CRadeon::~CRadeon()\n"));
if( fVirtualCard != NULL )
delete_area( fVirtualCardArea );
if( fSharedInfo != NULL )
delete_area( fSharedInfoArea );
if (fRegister != NULL)
delete_area( fRegisterArea );
if (fROM != NULL)
delete_area( fROMArea );
if (fHandle >= 0)
close(fHandle);
}
status_t CRadeon::InitCheck() const
{
return
(fHandle >= 0 &&
fRegister != NULL && fROM != NULL &&
fVirtualCard != NULL && fSharedInfo != NULL) ? B_OK : B_ERROR;
}
uint32 CRadeon::VirtualMemoryBase() const
{
return fSharedInfo->memory[mt_local].virtual_addr_start;
}
int CRadeon::Register(radeon_register index) const
{
return fRegister[index >> 2];
}
void CRadeon::SetRegister(radeon_register index, int value)
{
fRegister[index >> 2] = value;
}
int CRadeon::Register(radeon_register index, int mask) const
{
return fRegister[index >> 2] & mask;
}
void CRadeon::SetRegister(radeon_register index, int mask, int value)
{
#ifdef DEBUG
if ((value & ~mask) != 0)
PRINT(("CRadeon::SetRegister(0x%04x, 0x%08x, 0x%08x)\n", index, mask, value));
#endif
fRegister[index >> 2] = (fRegister[index >> 2] & ~mask) | (value & mask);
}
int CRadeon::VIPRegister(int device, int address)
{
radeon_vip_read vr;
status_t res;
vr.magic = RADEON_PRIVATE_DATA_MAGIC;
vr.channel = device;
vr.address = address;
res = ioctl( fHandle, RADEON_VIPREAD, &vr, sizeof( vr ));
if( res == B_OK )
return vr.data;
else
return -1;
}
void CRadeon::SetVIPRegister(int device, int address, int value)
{
radeon_vip_write vw;
vw.magic = RADEON_PRIVATE_DATA_MAGIC;
vw.channel = device;
vw.address = address;
vw.data = value;
ioctl( fHandle, RADEON_VIPWRITE, &vw, sizeof( vw ));
}
int CRadeon::FindVIPDevice( uint32 device_id )
{
radeon_find_vip_device fvd;
status_t res;
fvd.magic = RADEON_PRIVATE_DATA_MAGIC;
fvd.device_id = device_id;
res = ioctl( fHandle, RADEON_FINDVIPDEVICE, &fvd, sizeof( fvd ));
if( res == B_OK )
return fvd.channel;
else
return -1;
}
void CRadeon::GetPLLParameters(int & refFreq, int & refDiv, int & minFreq, int & maxFreq, int & xclock)
{
refFreq = fSharedInfo->pll.ref_freq;
refDiv = fSharedInfo->pll.ref_div;
minFreq = fSharedInfo->pll.min_pll_freq;
maxFreq = fSharedInfo->pll.max_pll_freq;
xclock = fSharedInfo->pll.xclk;
}
void CRadeon::GetMMParameters(radeon_video_tuner & tuner,
radeon_video_decoder & video,
radeon_video_clock & clock,
int & tunerPort,
int & compositePort,
int & svideoPort)
{
unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8);
unsigned char * fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8);
switch (fMMTable[0] & 0x1f) {
case 0x00:
tuner = C_RADEON_NO_TUNER;
break;
case 0x01:
tuner = C_RADEON_FI1236_MK1_NTSC;
break;
case 0x02:
tuner = C_RADEON_FI1236_MK2_NTSC_JAPAN;
break;
case 0x03:
tuner = C_RADEON_FI1216_MK2_PAL_BG;
break;
case 0x04:
tuner = C_RADEON_FI1246_MK2_PAL_I;
break;
case 0x05:
tuner = C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L;
break;
case 0x06:
tuner = C_RADEON_FI1236_MK2_NTSC;
break;
case 0x07:
tuner = C_RADEON_FI1256_MK2_SECAM_DK;
break;
case 0x08:
tuner = C_RADEON_FI1236_MK2_NTSC;
break;
case 0x09:
tuner = C_RADEON_FI1216_MK2_PAL_BG;
break;
case 0x0a:
tuner = C_RADEON_FI1246_MK2_PAL_I;
break;
case 0x0b:
tuner = C_RADEON_FI1216_MK2_PAL_BG_SECAM_L;
break;
case 0x0c:
tuner = C_RADEON_FI1236_MK2_NTSC;
break;
case 0x0d:
tuner = C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK;
break;
default:
tuner = C_RADEON_NO_TUNER;
break;
}
switch (fMMTable[5] & 0x0f) {
case 0x00:
video = C_RADEON_NO_VIDEO;
break;
case 0x01:
video = C_RADEON_BT819;
break;
case 0x02:
video = C_RADEON_BT829;
break;
case 0x03:
video = C_RADEON_BT829A;
break;
case 0x04:
video = C_RADEON_SA7111;
break;
case 0x05:
video = C_RADEON_SA7112;
break;
case 0x06:
video = C_RADEON_RAGE_THEATER;
break;
default:
video = C_RADEON_NO_VIDEO;
break;
}
switch (fMMTable[5] & 0xf0) {
case 0x00:
case 0x10:
case 0x20:
case 0x30:
clock = C_RADEON_NO_VIDEO_CLOCK;
break;
case 0x40:
clock = C_RADEON_VIDEO_CLOCK_28_63636_MHZ;
break;
case 0x50:
clock = C_RADEON_VIDEO_CLOCK_29_49892_MHZ;
break;
case 0x60:
clock = C_RADEON_VIDEO_CLOCK_27_00000_MHZ;
break;
case 0x70:
clock = C_RADEON_VIDEO_CLOCK_14_31818_MHZ;
break;
default:
clock = C_RADEON_NO_VIDEO_CLOCK;
break;
}
for (int port = 0; port < 4; port++) {
switch (fMMTable[7 + port] & 0x03) {
case 0x00:
// Unused or Invalid
break;
case 0x01:
// Tuner Input
tunerPort = 0;
break;
case 0x02:
// Front/Rear Composite Input
compositePort = (fMMTable[7 + port] & 0x04 ? 2 : 1);
break;
case 0x03:
// Front/Rear SVideo Input
svideoPort = (fMMTable[7 + port] & 0x04 ? 6 : 5);
break;
}
}
}
status_t CRadeon::AllocateGraphicsMemory(
memory_type_e memory_type, int32 size,
int32 *offset, int32 *handle )
{
radeon_alloc_mem am;
status_t res;
am.magic = RADEON_PRIVATE_DATA_MAGIC;
am.size = size;
am.memory_type = mt_local;
am.global = false;
res = ioctl( fHandle, RADEON_ALLOC_MEM, &am );
if( res != B_OK )
return res;
*handle = am.handle;
*offset = am.offset;
return B_OK;
}
void CRadeon::FreeGraphicsMemory(
memory_type_e memory_type, int32 handle )
{
radeon_free_mem fm;
fm.magic = RADEON_PRIVATE_DATA_MAGIC;
fm.memory_type = memory_type;
fm.global = false;
fm.handle = handle;
ioctl( fHandle, RADEON_FREE_MEM, &fm );
}
status_t CRadeon::DMACopy(
uint32 src, void *target, size_t size, bool lock_mem, bool contiguous )
{
radeon_dma_copy dc;
dc.magic = RADEON_PRIVATE_DATA_MAGIC;
dc.src = src;
dc.target = target;
dc.size = size;
dc.lock_mem = lock_mem;
dc.contiguous = contiguous;
return ioctl( fHandle, RADEON_DMACOPY, &dc );
}
status_t CRadeon::GetDeviceInformation(radeon_get_private_data & info)
{
info.magic = RADEON_PRIVATE_DATA_MAGIC;
return ioctl( fHandle, RADEON_GET_PRIVATE_DATA, &info, sizeof( info ));
}
status_t CRadeon::CloneArea(const char * name, area_id src_area,
area_id *cloned_area, void ** map)
{
int res = clone_area( name, map, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, src_area );
if( res < 0 ) {
return res;
} else {
*cloned_area = res;
return B_OK;
}
}
status_t CRadeon::WaitInterrupt(int * mask, int * sequence, bigtime_t * time, bigtime_t timeout)
{
radeon_wait_for_cap_irq wvc;
status_t status;
wvc.magic = RADEON_PRIVATE_DATA_MAGIC;
wvc.timeout = timeout;
status = ioctl( fHandle, RADEON_WAIT_FOR_CAP_IRQ, &wvc );
if( status == B_OK ) {
*mask = wvc.int_status;
*sequence = wvc.counter;
*time = wvc.timestamp;
}
return status;
}
#if 0
void CRadeon::PrintToStream()
{
// ATI ROM Signature
if (ROM(0) == 0x55 && ROM(1) == 0xAA) {
for (int offset = 0; offset < 128 - 9; offset++) {
if (ROM(offset + 0) == '7' &&
ROM(offset + 1) == '6' &&
ROM(offset + 2) == '1' &&
ROM(offset + 3) == '2' &&
ROM(offset + 4) == '9' &&
ROM(offset + 5) == '5' &&
ROM(offset + 6) == '5' &&
ROM(offset + 7) == '2' &&
ROM(offset + 8) == '0')
break;
}
}
// Video BIOS
unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8);
PRINT((
"----------------------------------------------------------------------\n"
"ATI RADEON VIDEO BIOS\n"
"\n"
"BIOS Revision: %03d.%03d.%03d%03d.%s\n"
"PCI Bus/Device/Function Code: 0x%04x\n"
"BIOS Runtime Segment Address: 0x%04x\n"
"I/O Base Address: 0x%04x\n"
"Subsystem Vendor ID: 0x%04x\n"
"Subsystem ID: 0x%04x\n"
"Post Vendor ID: 0x%04x\n"
"\n",
// OEM Revision (ID1.ID2.REVISION.CONFIG_FILE)
fVideoBIOS[2], fVideoBIOS[3],
fVideoBIOS[4], fVideoBIOS[5],
fROM + fVideoBIOS[0x10] + (fVideoBIOS[0x11] << 8),
// PCI bus, device, function code
fVideoBIOS[0x16] + (fVideoBIOS[0x17] << 8),
// ROM BIOS segment
fVideoBIOS[0x18] + (fVideoBIOS[0x19] << 8),
// I/O base address
fVideoBIOS[0x1a] + (fVideoBIOS[0x1b] << 8),
// Subsystem Vendor ID, Subsystem ID, Post Vendor ID
fVideoBIOS[0x1c] + (fVideoBIOS[0x1d] << 8),
fVideoBIOS[0x1e] + (fVideoBIOS[0x1f] << 8),
fVideoBIOS[0x20] + (fVideoBIOS[0x21] << 8)
));
// PLL Information
unsigned char *fPLL = fROM + fVideoBIOS[0x30] + (fVideoBIOS[0x31] << 8);
PRINT((
"----------------------------------------------------------------------\n"
"ATI RADEON PLL INFORMATION TABLE\n"
"\n"
"External Clock: %g MHz\n"
"Reference Frequency: %g MHz\n"
"Reference Divisor: %d\n"
"Min PLL Frequency: %g MHz\n"
"Max PLL Frequency: %g MHz\n"
"\n",
(fPLL[0x08] + (fPLL[0x09] << 8)) / 1000.0,
(fPLL[0x0e] + (fPLL[0x0f] << 8)) / 100.0,
fPLL[0x10] + (fPLL[0x11] << 8),
(fPLL[0x12] + (fPLL[0x13] << 8) + (fPLL[0x14] << 16) + (fPLL[0x15] << 24)) / 1000.0,
(fPLL[0x12] + (fPLL[0x16] << 8) + (fPLL[0x17] << 16) + (fPLL[0x18] << 24)) / 1000.0));
// TV Table
unsigned char * fTVTable = fROM + fVideoBIOS[0x32] + (fVideoBIOS[0x33] << 8);
PRINT((
"----------------------------------------------------------------------\n"
"ATI RADEON TV INFORMATION TABLE\n"
"\n"
"Table Signature: %c%c%c\n"
"Table Version: %d\n"
"Table Size: %d bytes\n"
"\n"
"TVOut Support: %s\n"
"BIOS built-in TV standard: %s\n"
"TVOut information: %s, %s MHz\n"
"\n"
"Run time supported TV standard:%s%s%s%s%s%s\n"
"Initialization time supported TV standard:%s%s%s%s%s%s\n"
"\n",
// Table signature, version and size
fTVTable[0x00],fTVTable[0x01], fTVTable[0x02],
fTVTable[0x03],
fTVTable[0x04] + ((int) fTVTable[0x05] << 8),
// TVOut support
fTVTable[0x06] == 'N' ? "TVOut chip not found" : "TVOut chip on board",
// BIOS built-in initialization TV standard
(fTVTable[0x07] & 0x0f) == 0x01 ? "NTSC" :
(fTVTable[0x07] & 0x0f) == 0x02 ? "PAL" :
(fTVTable[0x07] & 0x0f) == 0x03 ? "PAL-M" :
(fTVTable[0x07] & 0x0f) == 0x04 ? "PAL-60" :
(fTVTable[0x07] & 0x0f) == 0x05 ? "NTSC-J" :
(fTVTable[0x07] & 0x0f) == 0x06 ? "SCART-PAL" : "Reserved",
// TV Out information
(fTVTable[0x09] & 0x03) == 0x00 ? "Invalid" :
(fTVTable[0x09] & 0x03) == 0x01 ? "TV off, CRT on" :
(fTVTable[0x09] & 0x03) == 0x02 ? "TV on, CRT off" : "TV on, CRT on",
(fTVTable[0x09] & 0x0c) == 0x00 ? "29.498928713" :
(fTVTable[0x09] & 0x0c) == 0x04 ? "28.63636" :
(fTVTable[0x09] & 0x0c) == 0x08 ? "14.31818" : "27.0",
// Runtime supported TV standard
(fTVTable[0x0a] & 0x01) != 0 ? " NTSC" : "",
(fTVTable[0x0a] & 0x02) != 0 ? " PAL" : "",
(fTVTable[0x0a] & 0x04) != 0 ? " PAL-M" : "",
(fTVTable[0x0a] & 0x08) != 0 ? " PAL-60" : "",
(fTVTable[0x0a] & 0x10) != 0 ? " NTSC-J" : "",
(fTVTable[0x0a] & 0x20) != 0 ? " SCART-PAL" : "",
// Initialization time supported TV standard
(fTVTable[0x0b] & 0x01) != 0 ? " NTSC" : "",
(fTVTable[0x0b] & 0x02) != 0 ? " PAL" : "",
(fTVTable[0x0b] & 0x04) != 0 ? " PAL-M" : "",
(fTVTable[0x0b] & 0x08) != 0 ? " PAL-60" : "",
(fTVTable[0x0b] & 0x10) != 0 ? " NTSC-J" : "",
(fTVTable[0x0b] & 0x20) != 0 ? " SCART-PAL" : ""
));
// Hardware Configuration Table
unsigned char * fHWTable = fROM + fVideoBIOS[0x36] + (fVideoBIOS[0x37] << 8);
PRINT((
"----------------------------------------------------------------------\n"
"ATI RADEON HARDWARE CONFIGURATION TABLE\n"
"\n"
"Table Signature: %c%c%c%c\n"
"Table Revision: %d\n"
"Table Size: %d\n"
"\n"
"I2C Type: %s\n"
"TVOut Support: %s\n"
"Video Out Crystal: %s\n"
"ImpactTV Data Port: %s\n"
"\n"
"Video Port Capability:\n"
" AMC/DVS0 Video Port: %s\n"
" Zoom Video Port: %s\n"
" AMC/DVS1 Video Port: %s\n"
" VIP 16-bit Video Port: %s\n"
"\n"
"Host Port Configuration: %s\n"
"\n",
// Table Signature, Revision, Size
fHWTable[0x00], fHWTable[0x01], fHWTable[0x02], fHWTable[0x03],
fHWTable[0x04], fHWTable[0x05],
// I2C type
(fHWTable[0x06] & 0x0f) == 0x00 ? "Normal GP I/O (data=GP_IO2, clock=GP_IO1)" :
(fHWTable[0x06] & 0x0f) == 0x01 ? "ImpacTV GP I/O" :
(fHWTable[0x06] & 0x0f) == 0x02 ? "Dedicated I2C Pin" :
(fHWTable[0x06] & 0x0f) == 0x03 ? "GP I/O (data=GP_IO12, clock=GP_IO13)" :
(fHWTable[0x06] & 0x0f) == 0x04 ? "GP I/O (data=GPIO12, clock=GPIO10)" :
(fHWTable[0x06] & 0x0f) == 0x05 ? "RAGE THEATER I2C Master" :
(fHWTable[0x06] & 0x0f) == 0x06 ? "Rage128 MPP2 Pin" :
(fHWTable[0x06] & 0x0f) == 0x0f ? "No I2C Configuration" : "Reserved",
// TVOut support
(fHWTable[0x07] & 0x0f) == 0x00 ? "No TVOut supported" :
(fHWTable[0x07] & 0x0f) == 0x01 ? "ImpactTV1 supported" :
(fHWTable[0x07] & 0x0f) == 0x02 ? "ImpactTV2 supported" :
(fHWTable[0x07] & 0x0f) == 0x03 ? "Improved ImpactTV2 supported" :
(fHWTable[0x07] & 0x0f) == 0x04 ? "RAGE THEATER supported" : "Reserved",
// Video Out Crystal
(fHWTable[0x07] & 0x70) == 0x00 ? "TVOut not installed" :
(fHWTable[0x07] & 0x70) == 0x10 ? "28.63636 MHz" :
(fHWTable[0x07] & 0x70) == 0x20 ? "29.49892713 MHz" :
(fHWTable[0x07] & 0x70) == 0x30 ? "27.0 MHz" :
(fHWTable[0x07] & 0x70) == 0x40 ? "14.31818 MHz" : "Reserved",
// ImpactTV data port
(fHWTable[0x07] & 0x80) == 0x00 ? "MPP1" : "MPP2",
// Video Port Capability
(fHWTable[0x08] & 0x01) == 0x00 ? "Not Supported" : "Supported",
(fHWTable[0x08] & 0x02) == 0x00 ? "Not Supported" : "Supported",
(fHWTable[0x08] & 0x04) == 0x00 ? "Not Supported" : "Supported",
(fHWTable[0x08] & 0x08) == 0x00 ? "Not Supported" : "Supported",
// Host Port Configuration
(fHWTable[0x09] & 0x0f) == 0x00 ? "No Host Port" :
(fHWTable[0x09] & 0x0f) == 0x01 ? "MPP Host Port" :
(fHWTable[0x09] & 0x0f) == 0x02 ? "2 bit VIP Host Port" :
(fHWTable[0x09] & 0x0f) == 0x03 ? "4 bit VIP Host Port" :
(fHWTable[0x09] & 0x0f) == 0x04 ? "8 bit VIP Host Port" : "Reserved"
));
// Multimedia Table
unsigned char * fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8);
PRINT((
"----------------------------------------------------------------------\n"
"ATI RADEON MULTIMEDIA TABLE\n"
"\n"
"Table Revision: %d\n"
"Table Size: %d bytes\n"
"\n"
"Tuner Chip: %s\n"
"Tuner Input: %s\n"
"Tuner Voltage Regulator: %s\n"
"\n"
"Audio Chip: %s\n"
"FM Audio Decoder: %s\n"
"Audio Scrambling: %s\n"
"\n"
"Product Type: %s, Revision %d\n"
"Product ID: %s\n"
"\n"
"I2S Input Configuration: %s\n"
"I2S Output Configuration: %s\n"
"I2S Audio Chip: %s\n"
"S/PDIF Output Configuration: %s\n"
"\n"
"Video Decoder: %s\n"
"Video Standard/Crystal: %s\n"
"Video Decoder Host Config: %s\n"
"Hardware Teletext: %s\n"
"\n"
"Video Input:\n"
" 0: %s, %s (ID %d)\n"
" 1: %s, %s (ID %d)\n"
" 2: %s, %s (ID %d)\n"
" 3: %s, %s (ID %d)\n"
" 4: %s, %s (ID %d)\n"
"\n",
/* Hardware Table */
fMMTable[-2], fMMTable[-1],
/* Tuner Type */
(fMMTable[0] & 0x1f) == 0x00 ? "No Tuner" :
(fMMTable[0] & 0x1f) == 0x01 ? "Philips FI1236 MK1 NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x02 ? "Philips FI1236 MK2 NTSC M/N Japan" :
(fMMTable[0] & 0x1f) == 0x03 ? "Philips FI1216 MK2 PAL B/G" :
(fMMTable[0] & 0x1f) == 0x04 ? "Philips FI1246 MK2 PAL I" :
(fMMTable[0] & 0x1f) == 0x05 ? "Philips FI1216 MF MK2 PAL B/G, SECAM L/L'" :
(fMMTable[0] & 0x1f) == 0x06 ? "Philips FI1236 MK2 NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x07 ? "Philips FI1256 MK2 SECAM D/K" :
(fMMTable[0] & 0x1f) == 0x08 ? "Philips FM1236 MK2 NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x09 ? "Philips FI1216 MK2 PAL B/G - External Tuner POD" :
(fMMTable[0] & 0x1f) == 0x0a ? "Philips FI1246 MK2 PAL I - External Tuner POD" :
(fMMTable[0] & 0x1f) == 0x0b ? "Philips FI1216 MF MK2 PAL B/G, SECAM L/L' - External Tuner POD" :
(fMMTable[0] & 0x1f) == 0x0c ? "Philips FI1236 MK2 NTSC M/N North America - External Tuner POD" :
(fMMTable[0] & 0x1f) == 0x0d ? "Temic FN5AL RF3X7595 PAL I/B/G/DK & SECAM DK" :
(fMMTable[0] & 0x1f) == 0x10 ? "Alps TSBH5 NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x11 ? "Alps TSC?? NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x12 ? "Alps TSCH5 NTSC M/N North America" :
(fMMTable[0] & 0x1f) == 0x1f ? "Unknown Tuner Type" : "Reserved",
/* Video Input for Tuner */
(fMMTable[0] & 0xe0) == 0x00 ? "Video Input 0" :
(fMMTable[0] & 0xe0) == 0x20 ? "Video Input 1" :
(fMMTable[0] & 0xe0) == 0x40 ? "Video Input 2" :
(fMMTable[0] & 0xe0) == 0x60 ? "Video Input 3" :
(fMMTable[0] & 0xe0) == 0x80 ? "Video Input 4" : "Reserved",
/* Tuner Voltage */
(fMMTable[3] & 0x03) == 0x00 ? "No Tuner Power down feature" :
(fMMTable[3] & 0x03) == 0x01 ? "Tuner Power down feature" : "Reserved",
/* Audio Chip Type */
(fMMTable[1] & 0x0f) == 0x00 ? "Philips TEA5582 NTSC Stereo, no dbx, no volume" :
(fMMTable[1] & 0x0f) == 0x01 ? "Mono with audio mux" :
(fMMTable[1] & 0x0f) == 0x02 ? "Philips TDA9850 NTSC N.A. Stereo, dbx, mux, no volume" :
(fMMTable[1] & 0x0f) == 0x03 ? "Sony CXA2020S Japan NTSC Stereo, mux, no volume" :
(fMMTable[1] & 0x0f) == 0x04 ? "ITT MSP3410D Europe Stereo, volume, internal mux" :
(fMMTable[1] & 0x0f) == 0x05 ? "Crystal CS4236B" :
(fMMTable[1] & 0x0f) == 0x06 ? "Philips TDA9851 NTSC Stereo, volume, no dbx, no mux" :
(fMMTable[1] & 0x0f) == 0x07 ? "ITT MSP3415 (Europe)" :
(fMMTable[1] & 0x0f) == 0x08 ? "ITT MSP3430 (N.A.)" :
(fMMTable[1] & 0x0f) == 0x0f ? "No Audio Chip Installed" : "Reserved",
/* FM Audio Decoder */
(fMMTable[3] & 0x30) == 0x00 ? "No FM Audio Decoder" :
(fMMTable[3] & 0x30) == 0x10 ? "FM Audio Decoder (Rohm BA1332F)" : "Reserved",
/* Audio Scrambling */
(fMMTable[3] & 0x80) == 0x00 ? "Not Supported" : "Supported",
/* Product Type */
(fMMTable[1] & 0x10) == 0x00 ? "OEM Product" : "ATI Product",
/* OEM Revision */
(fMMTable[1] & 0xe0) >> 5,
/* Product ID */
(fMMTable[1] & 0x10) == 0x00 ? "<OEM ID>" :
(
fMMTable[2] == 0x00 ? "ATI Prototype Board" :
fMMTable[2] == 0x01 ? "ATI All in Wonder" :
fMMTable[2] == 0x02 ? "ATI All in Wonder Pro, no MPEG/DVD decoder" :
fMMTable[2] == 0x03 ? "ATI All in Wonder Pro, CD11 or similar MPEG/DVD decoder on MPP" :
fMMTable[2] == 0x04 ? "ATI All in Wonder Plus" :
fMMTable[2] == 0x05 ? "ATI Kitchener Board" :
fMMTable[2] == 0x06 ? "ATI Toronto Board (analog audio)" :
fMMTable[2] == 0x07 ? "ATI TV-Wonder" :
fMMTable[2] == 0x08 ? "ATI Victoria Board (Rage XL plus RAGE THEATER)" : "Reserved"
),
/* I2S Input/Output Configuration */
(fMMTable[4] & 0x01) == 0x00 ? "Not Supported" : "Supported",
(fMMTable[4] & 0x02) == 0x00 ? "Not Supported" : "Supported",
/* I2S Audio Chip */
(fMMTable[4] & 0x1c) == 0x00 ? "TDA1309_32Strap" :
(fMMTable[4] & 0x1c) == 0x04 ? "TDA1309_64Strap" :
(fMMTable[4] & 0x1c) == 0x08 ? "ITT MSP3430" :
(fMMTable[4] & 0x1c) == 0x0c ? "ITT MSP3415" : "Reserved",
/* S/PDIF Output Config */
(fMMTable[4] & 0x20) == 0x00 ? "Not Supported" : "Supported",
/* Video Decoder Type */
(fMMTable[5] & 0x0f) == 0x00 ? "No Video Decoder" :
(fMMTable[5] & 0x0f) == 0x01 ? "Bt819" :
(fMMTable[5] & 0x0f) == 0x02 ? "Bt829" :
(fMMTable[5] & 0x0f) == 0x03 ? "Bt829A" :
(fMMTable[5] & 0x0f) == 0x04 ? "Philips SA7111" :
(fMMTable[5] & 0x0f) == 0x05 ? "Philips SA7112 or SA7112A" :
(fMMTable[5] & 0x0f) == 0x06 ? "RAGE THEATER" : "Reserved",
/* Video-In Standard/Crystal */
(fMMTable[5] & 0xf0) == 0x00 ? "NTSC and PAL Crystals installed" :
(fMMTable[5] & 0xf0) == 0x10 ? "NTSC Crystal only" :
(fMMTable[5] & 0xf0) == 0x20 ? "PAL Crystal only" :
(fMMTable[5] & 0xf0) == 0x30 ? "NTSC, PAL, SECAM Ssingle crystal for Bt829 and Bt879" :
(fMMTable[5] & 0xf0) == 0x40 ? "28.63636 MHz Crystal" :
(fMMTable[5] & 0xf0) == 0x50 ? "29.49892713 MHz Crystal" :
(fMMTable[5] & 0xf0) == 0x60 ? "27.0 MHz Crystal" :
(fMMTable[5] & 0xf0) == 0x70 ? "14.31818 MHz Crystal" : "Reserved",
/* Video Decoder Host Config */
(fMMTable[6] & 0x07) == 0x00 ? "I2C Device" :
(fMMTable[6] & 0x07) == 0x01 ? "MPP Device" :
(fMMTable[6] & 0x07) == 0x02 ? "2 bits VIP Device" :
(fMMTable[6] & 0x07) == 0x03 ? "4 bits VIP Device" :
(fMMTable[6] & 0x07) == 0x04 ? "8 bits VIP Device" :
(fMMTable[6] & 0x07) == 0x07 ? "PCI Device" : "Reserved",
/* Hardware Teletext */
(fMMTable[3] & 0x0c) == 0x00 ? "No Hardware Teletext" :
(fMMTable[3] & 0x0c) == 0x04 ? "Philips SAA5281" : "Reserved",
/* Video Input 0 */
(fMMTable[7] & 0x03) == 0x00 ? "Unused/Invalid" :
(fMMTable[7] & 0x03) == 0x01 ? "Tuner Input" :
(fMMTable[7] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
(fMMTable[7] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
(fMMTable[7] & 0x38) >> 3,
/* Video Input 1 */
(fMMTable[8] & 0x03) == 0x00 ? "Unused/Invalid" :
(fMMTable[8] & 0x03) == 0x01 ? "Tuner Input" :
(fMMTable[8] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
(fMMTable[8] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
(fMMTable[8] & 0x38) >> 3,
/* Video Input 2 */
(fMMTable[9] & 0x03) == 0x00 ? "Unused/Invalid" :
(fMMTable[9] & 0x03) == 0x01 ? "Tuner Input" :
(fMMTable[9] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
(fMMTable[9] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
(fMMTable[9] & 0x38) >> 3,
/* Video Input 3 */
(fMMTable[10] & 0x03) == 0x00 ? "Unused/Invalid" :
(fMMTable[10] & 0x03) == 0x01 ? "Tuner Input" :
(fMMTable[10] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
(fMMTable[10] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
(fMMTable[10] & 0x38) >> 3,
/* Video Input 4 */
(fMMTable[11] & 0x03) == 0x00 ? "Unused/Invalid" :
(fMMTable[11] & 0x03) == 0x01 ? "Tuner Input" :
(fMMTable[11] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
(fMMTable[11] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
(fMMTable[11] & 0x38) >> 3
));
}
#endif
@@ -0,0 +1,405 @@
/******************************************************************************
/
/ File: Radeon.h
/
/ Description: ATI Radeon Graphics Chip interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __RADEON_H__
#define __RADEON_H__
#include "radeon_interface.h"
#define BITS(a) int((0xffffffffU>>(31-(1?a)))&(0xffffffffU<<(0?a)))
enum radeon_video_tuner {
C_RADEON_NO_TUNER = 0,
C_RADEON_FI1236_MK1_NTSC = 1,
C_RADEON_FI1236_MK2_NTSC_JAPAN = 2,
C_RADEON_FI1216_MK2_PAL_BG = 3,
C_RADEON_FI1246_MK2_PAL_I = 4,
C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L = 5,
C_RADEON_FI1236_MK2_NTSC = 6,
C_RADEON_FI1256_MK2_SECAM_DK = 7,
C_RADEON_FI1216_MK2_PAL_BG_SECAM_L = 8,
C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK = 9
};
enum radeon_video_clock {
C_RADEON_NO_VIDEO_CLOCK = 0,
C_RADEON_VIDEO_CLOCK_28_63636_MHZ = 1,
C_RADEON_VIDEO_CLOCK_29_49892_MHZ = 2,
C_RADEON_VIDEO_CLOCK_27_00000_MHZ = 3,
C_RADEON_VIDEO_CLOCK_14_31818_MHZ = 4
};
enum radeon_video_decoder {
C_RADEON_NO_VIDEO = 0,
C_RADEON_BT819 = 1,
C_RADEON_BT829 = 2,
C_RADEON_BT829A = 3,
C_RADEON_SA7111 = 4,
C_RADEON_SA7112 = 5,
C_RADEON_RAGE_THEATER = 6
};
enum radeon_register {
C_RADEON_VIDEOMUX_CNTL = 0x0190,
C_RADEON_VIPH_INT_SEL = BITS(0:0),
C_RADEON_ROM_CLK_DIVIDE = BITS(20:16),
C_RADEON_STR_ROMCLK = BITS(21:21),
C_RADEON_VIP_INTERNAL_DEBUG_SEL = BITS(24:22),
// I2C
C_RADEON_I2C_CNTL_0 = 0x0090,
C_RADEON_I2C_DONE = BITS(0:0),
C_RADEON_I2C_NACK = BITS(1:1),
C_RADEON_I2C_HALT = BITS(2:2),
C_RADEON_I2C_SOFT_RST = BITS(5:5),
C_RADEON_I2C_DRIVE_EN = BITS(6:6),
C_RADEON_I2C_DRIVE_SEL = BITS(7:7),
C_RADEON_I2C_DRIVE_SEL_10_MCLKS = 0 << 7,
C_RADEON_I2C_DRIVE_SEL_20_MCLKS = 1 << 7,
C_RADEON_I2C_START = BITS(8:8),
C_RADEON_I2C_STOP = BITS(9:9),
C_RADEON_I2C_RECEIVE = BITS(10:10),
C_RADEON_I2C_ABORT = BITS(11:11),
C_RADEON_I2C_GO = BITS(12:12),
C_RADEON_I2C_PRESCALE = BITS(31:16),
C_RADEON_I2C_CNTL_1 = 0x0094,
C_RADEON_I2C_DATA_COUNT = BITS(3:0),
C_RADEON_I2C_ADDR_COUNT = BITS(10:8),
C_RADEON_I2C_SEL = BITS(16:16),
C_RADEON_I2C_EN = BITS(17:17),
C_RADEON_I2C_TIME_LIMIT = BITS(31:24),
C_RADEON_I2C_DATA = 0x0098,
C_RADEON_I2C_DATA_MASK = BITS(7:0),
// Capture
C_RADEON_CAP_INT_CNTL = 0x0908,
C_RADEON_CAP0_BUF0_INT_EN = BITS(0:0),
C_RADEON_CAP0_BUF0_EVEN_INT_EN = BITS(1:1),
C_RADEON_CAP0_BUF1_INT_EN = BITS(2:2),
C_RADEON_CAP0_BUF1_EVEN_INT_EN = BITS(3:3),
C_RADEON_CAP0_VBI0_INT_EN = BITS(4:4),
C_RADEON_CAP0_VBI1_INT_EN = BITS(5:5),
C_RADEON_CAP0_ONESHOT_INT_EN = BITS(6:6),
C_RADEON_CAP0_ANC0_INT_EN = BITS(7:7),
C_RADEON_CAP0_ANC1_INT_EN = BITS(8:8),
C_RADEON_CAP0_VBI2_INT_EN = BITS(9:9),
C_RADEON_CAP0_VBI3_INT_EN = BITS(10:10),
C_RADEON_CAP0_ANC2_INT_EN = BITS(11:11),
C_RADEON_CAP0_ANC3_INT_EN = BITS(12:12),
C_RADEON_CAP_INT_STATUS = 0x090C,
C_RADEON_CAP0_BUF0_INT = BITS(0:0),
C_RADEON_CAP0_BUF0_INT_AK = BITS(0:0),
C_RADEON_CAP0_BUF0_EVEN_INT = BITS(1:1),
C_RADEON_CAP0_BUF0_EVEN_INT_AK = BITS(1:1),
C_RADEON_CAP0_BUF1_INT = BITS(2:2),
C_RADEON_CAP0_BUF1_INT_AK = BITS(2:2),
C_RADEON_CAP0_BUF1_EVEN_INT = BITS(3:3),
C_RADEON_CAP0_BUF1_EVEN_INT_AK = BITS(3:3),
C_RADEON_CAP0_VBI0_INT = BITS(4:4),
C_RADEON_CAP0_VBI0_INT_AK = BITS(4:4),
C_RADEON_CAP0_VBI1_INT = BITS(5:5),
C_RADEON_CAP0_VBI1_INT_AK = BITS(5:5),
C_RADEON_CAP0_ONESHOT_INT = BITS(6:6),
C_RADEON_CAP0_ONESHOT_INT_AK = BITS(6:6),
C_RADEON_CAP0_ANC0_INT = BITS(7:7),
C_RADEON_CAP0_ANC0_INT_AK = BITS(7:7),
C_RADEON_CAP0_ANC1_INT = BITS(8:8),
C_RADEON_CAP0_ANC1_INT_AK = BITS(8:8),
C_RADEON_CAP0_VBI2_INT = BITS(9:9),
C_RADEON_CAP0_VBI2_INT_AK = BITS(9:9),
C_RADEON_CAP0_VBI3_INT = BITS(10:10),
C_RADEON_CAP0_VBI3_INT_AK = BITS(10:10),
C_RADEON_CAP0_ANC2_INT = BITS(11:11),
C_RADEON_CAP0_ANC2_INT_AK = BITS(11:11),
C_RADEON_CAP0_ANC3_INT = BITS(12:12),
C_RADEON_CAP0_ANC3_INT_AK = BITS(12:12),
C_RADEON_FCP_CNTL = 0x0910,
C_RADEON_FCP0_SRC_SEL = BITS(2:0),
C_RADEON_FCP0_SRC_PCICLK = 0 << 0,
C_RADEON_FCP0_SRC_PCLK = 1 << 0,
C_RADEON_FCP0_SRC_PCLKb = 2 << 0,
C_RADEON_FCP0_SRC_HREF = 3 << 0,
C_RADEON_FCP0_SRC_GND = 4 << 0,
C_RADEON_FCP0_SRC_HREFb = 5 << 0,
C_RADEON_CAP0_BUF0_OFFSET = 0x0920,
C_RADEON_CAP0_BUF1_OFFSET = 0x0924,
C_RADEON_CAP0_BUF0_EVEN_OFFSET = 0x0928,
C_RADEON_CAP0_BUF1_EVEN_OFFSET = 0x092C,
C_RADEON_CAP0_BUF_PITCH = 0x0930,
C_RADEON_CAP0_BUF_PITCH_MASK = BITS(11:0),
C_RADEON_CAP0_V_WINDOW = 0x0934,
C_RADEON_CAP0_V_START = BITS(11:0),
C_RADEON_CAP0_V_END = BITS(27:16),
C_RADEON_CAP0_H_WINDOW = 0x0938,
C_RADEON_CAP0_H_START = BITS(11:0),
C_RADEON_CAP0_H_WIDTH = BITS(27:16),
C_RADEON_CAP0_VBI0_OFFSET = 0x093C,
C_RADEON_CAP0_VBI1_OFFSET = 0x0940,
C_RADEON_CAP0_VBI_V_WINDOW = 0x0944,
C_RADEON_CAP0_VBI_V_START = BITS(11:0),
C_RADEON_CAP0_VBI_V_END = BITS(27:16),
C_RADEON_CAP0_VBI_H_WINDOW = 0x0948,
C_RADEON_CAP0_VBI_H_START = BITS(11:0),
C_RADEON_CAP0_VBI_H_WIDTH = BITS(27:16),
C_RADEON_CAP0_PORT_MODE_CNTL = 0x094C,
C_RADEON_CAP0_PORT_WIDTH = BITS(1:1),
C_RADEON_CAP0_PORT_WIDTH_8_BITS = 0 << 1,
C_RADEON_CAP0_PORT_WIDTH_16_BITS = 1 << 1,
C_RADEON_CAP0_PORT_BYTE_USED = BITS(2:2),
C_RADEON_CAP0_PORT_LOWER_BYTE_USED = 0 << 2,
C_RADEON_CAP0_PORT_UPPER_BYTE_USED = 1 << 2,
C_RADEON_CAP0_TRIG_CNTL = 0x0950,
C_RADEON_CAP0_TRIGGER_R = BITS(1:0),
C_RADEON_CAP0_TRIGGER_R_COMPLETE = 0 << 0,
C_RADEON_CAP0_TRIGGER_R_PENDING = 1 << 0,
C_RADEON_CAP0_TRIGGER_R_IN_PROGRESS = 2 << 0,
C_RADEON_CAP0_TRIGGER_W = BITS(0:0),
C_RADEON_CAP0_TRIGGER_W_NO_ACTION = 0 << 0,
C_RADEON_CAP0_TRIGGER_W_CAPTURE = 1 << 0,
C_RADEON_CAP0_EN = BITS(4:4),
C_RADEON_CAP0_VSYNC_CNT_R = BITS(15:8),
C_RADEON_CAP0_VSYNC_CLR = BITS(16:16),
C_RADEON_CAP0_DEBUG = 0x0954,
C_RADEON_CAP0_H_STATUS = BITS(11:0),
C_RADEON_CAP0_V_STATUS = BITS(27:16),
C_RADEON_CAP0_V_SYNC = BITS(28:28),
C_RADEON_CAP0_CONFIG = 0x0958,
C_RADEON_CAP0_INPUT_MODE = BITS(0:0),
C_RADEON_CAP0_INPUT_MODE_ONESHOT = 0 << 0,
C_RADEON_CAP0_INPUT_MODE_CONTINUOUS = 1 << 0,
C_RADEON_CAP0_START_FIELD = BITS(1:1),
C_RADEON_CAP0_START_ODD_FIELD = 0 << 1,
C_RADEON_CAP0_START_EVEN_FIELD = 1 << 1,
C_RADEON_CAP0_START_BUF_R = BITS(2:2),
C_RADEON_CAP0_START_BUF_W = BITS(3:3),
C_RADEON_CAP0_BUF_TYPE = BITS(5:4),
C_RADEON_CAP0_BUF_TYPE_FIELD = 0 << 4,
C_RADEON_CAP0_BUF_TYPE_ALTERNATING = 1 << 4,
C_RADEON_CAP0_BUF_TYPE_FRAME = 2 << 4,
C_RADEON_CAP0_ONESHOT_MODE = BITS(6:6),
C_RADEON_CAP0_ONESHOT_MODE_FIELD = 0 << 6,
C_RADEON_CAP0_ONESHOT_MODE_FRAME = 1 << 6,
C_RADEON_CAP0_BUF_MODE = BITS(8:7),
C_RADEON_CAP0_BUF_MODE_SINGLE = 0 << 7,
C_RADEON_CAP0_BUF_MODE_DOUBLE = 1 << 7,
C_RADEON_CAP0_BUF_MODE_TRIPLE = 2 << 7,
C_RADEON_CAP0_MIRROR_EN = BITS(9:9),
C_RADEON_CAP0_ONESHOT_MIRROR_EN = BITS(10:10),
C_RADEON_CAP0_VIDEO_SIGNED_UV = BITS(11:11),
C_RADEON_CAP0_ANC_DECODE_EN = BITS(12:12),
C_RADEON_CAP0_VBI_EN = BITS(13:13),
C_RADEON_CAP0_SOFT_PULL_DOWN_EN = BITS(14:14),
C_RADEON_CAP0_VIP_EXTEND_FLAG_EN = BITS(15:15),
C_RADEON_CAP0_FAKE_FIELD_EN = BITS(16:16),
C_RADEON_CAP0_FIELD_START_LINE_DIFF = BITS(18:17),
C_RADEON_CAP0_HORZ_DOWN = BITS(20:19),
C_RADEON_CAP0_HORZ_DOWN_1X = 0 << 19,
C_RADEON_CAP0_HORZ_DOWN_2X = 1 << 19,
C_RADEON_CAP0_HORZ_DOWN_3X = 2 << 19,
C_RADEON_CAP0_VERT_DOWN = BITS(22:21),
C_RADEON_CAP0_VERT_DOWN_1X = 0 << 21,
C_RADEON_CAP0_VERT_DOWN_2X = 1 << 21,
C_RADEON_CAP0_VERT_DOWN_3X = 2 << 21,
C_RADEON_CAP0_STREAM_FORMAT = BITS(25:23),
C_RADEON_CAP0_STREAM_BROOKTREE = 0 << 23,
C_RADEON_CAP0_STREAM_CCIR656 = 1 << 23,
C_RADEON_CAP0_STREAM_ZV = 2 << 23,
C_RADEON_CAP0_STREAM_VIP = 3 << 23,
C_RADEON_CAP0_STREAM_TRANSPORT = 4 << 23,
C_RADEON_CAP0_HDWNS_DEC = BITS(26:26),
C_RADEON_CAP0_DOWNSCALER = 0 << 26,
C_RADEON_CAP0_DECIMATOR = 1 << 26,
C_RADEON_CAP0_VIDEO_IN_FORMAT = BITS(29:29),
C_RADEON_CAP0_VIDEO_IN_YVYU422 = 0 << 29,
C_RADEON_CAP0_VIDEO_IN_VYUY422 = 1 << 29,
C_RADEON_CAP0_VBI_HORZ_DOWN = BITS(31:30),
C_RADEON_CAP0_VBI_HORZ_DOWN_1X = 0 << 30,
C_RADEON_CAP0_VBI_HORZ_DOWN_2X = 1 << 30,
C_RADEON_CAP0_VBI_HORZ_DOWN_4X = 2 << 30,
C_RADEON_CAP0_ANC0_OFFSET = 0x095C,
C_RADEON_CAP0_ANC1_OFFSET = 0x0960,
C_RADEON_CAP0_ANC_H_WINDOW = 0x0964,
C_RADEON_CAP0_ANC_WIDTH = BITS(11:0),
C_RADEON_CAP0_VIDEO_SYNC_TEST = 0x0968,
C_RADEON_CAP0_TEST_VID_SOF = BITS(0:0),
C_RADEON_CAP0_TEST_VID_EOF = BITS(1:1),
C_RADEON_CAP0_TEST_VID_EOL = BITS(2:2),
C_RADEON_CAP0_TEST_VID_FIELD = BITS(3:3),
C_RADEON_CAP0_TEST_SYNC_EN = BITS(5:5),
C_RADEON_CAP0_ONESHOT_BUF_OFFSET = 0x096C,
C_RADEON_CAP0_BUF_STATUS = 0x0970,
C_RADEON_CAP0_PRE_VID_BUF = BITS(1:0),
C_RADEON_CAP0_CUR_VID_BUF = BITS(3:2),
C_RADEON_CAP0_PRE_FIELD = BITS(4:4),
C_RADEON_CAP0_CUR_FIELD = BITS(5:5),
C_RADEON_CAP0_PRE_VBI_BUF = BITS(7:6),
C_RADEON_CAP0_CUR_VBI_BUF = BITS(9:8),
C_RADEON_CAP0_VBI_BUF_STATUS = BITS(10:10),
C_RADEON_CAP0_PRE_ANC_BUF = BITS(12:11),
C_RADEON_CAP0_CUR_ANC_BUF = BITS(14:13),
C_RADEON_CAP0_ANC_BUF_STATUS = BITS(16:16),
C_RADEON_CAP0_ANC_PRE_BUF_CNT = BITS(27:16),
C_RADEON_CAP0_VIP_INC = BITS(28:28),
C_RADEON_CAP0_VIP_PRE_REPEAT_FIELD = BITS(29:29),
C_RADEON_CAP0_CAP_BUF_STATUS = BITS(30:30),
C_RADEON_CAP0_VBI2_OFFSET = 0x0980,
C_RADEON_CAP0_VBI3_OFFSET = 0x0984,
C_RADEON_CAP0_ANC2_OFFSET = 0x0988,
C_RADEON_CAP0_ANC3_OFFSET = 0x098C,
C_RADEON_VBI_BUFFER_CONTROL = 0x0900,
C_RADEON_CAP0_BUFFER_WATER_MARK = BITS(4:0),
C_RADEON_FULL_BUFFER_EN = BITS(16:16),
C_RADEON_CAP0_ANC_VBI_QUAD_BUF = BITS(17:17),
C_RADEON_VID_BUFFER_RESET = BITS(20:20),
C_RADEON_CAP_SWAP = BITS(22:21),
C_RADEON_CAP0_BUFFER_EMPTY_R = BITS(24:24),
// Test and Debug control
C_RADEON_TEST_DEBUG_CNTL = 0x0120,
C_RADEON_TEST_DEBUG_OUT_EN = 0x00000001
};
class CRadeonRect {
public:
CRadeonRect();
CRadeonRect(int left, int top, int right, int bottom);
int Left() const;
int Top() const;
int Right() const;
int Bottom() const;
int Width() const;
int Height() const;
void SetLeft(int value);
void SetTop(int value);
void SetRight(int value);
void SetBottom(int value);
void SetTo(int left, int top, int right, int bottom);
void MoveTo(int left, int top);
void ResizeTo(int width, int height);
private:
int fLeft;
int fTop;
int fRight;
int fBottom;
};
class CRadeon {
public:
CRadeon( const char *dev_name );
~CRadeon();
status_t InitCheck() const;
uint32 VirtualMemoryBase() const;
public:
int Register(radeon_register index) const;
void SetRegister(radeon_register index, int value);
int Register(radeon_register index, int mask) const;
void SetRegister(radeon_register index, int mask, int value);
int VIPRegister(int device, int address);
void SetVIPRegister(int device, int address, int value);
int FindVIPDevice( uint32 device_id );
public:
void GetPLLParameters(int & refFreq, int & refDiv, int & minFreq, int & maxFreq, int & xclock);
void GetMMParameters(radeon_video_tuner & tuner,
radeon_video_decoder & video,
radeon_video_clock & clock,
int & tunerPort,
int & compositePort,
int & svideoPort);
public:
status_t AllocateGraphicsMemory(
memory_type_e memory_type, int32 size,
int32 *offset, int32 *handle );
void FreeGraphicsMemory(
memory_type_e memory_type, int32 handle );
status_t DMACopy(
uint32 src, void *target, size_t size, bool lock_mem, bool contiguous );
public:
status_t GetDeviceInformation(radeon_get_private_data & info);
status_t WaitInterrupt(int * mask, int * sequence, bigtime_t * time, bigtime_t timeout);
status_t CloneArea(const char * name, area_id src_area,
area_id *cloned_area, void ** map);
private:
int fHandle;
unsigned int * fRegister;
unsigned char * fROM;
virtual_card *fVirtualCard;
shared_info *fSharedInfo;
area_id fRegisterArea;
area_id fROMArea;
area_id fVirtualCardArea;
area_id fSharedInfoArea;
};
template <typename T>
inline T Clamp(T value, T min, T max)
{
return (value < min ? min : value > max ? max : value);
}
#endif
@@ -0,0 +1,432 @@
/******************************************************************************
/
/ File: RadeonAddOn.cpp
/
/ Description: ATI Radeon Video Capture Media AddOn for BeOS.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <support/Autolock.h>
#include <media/MediaFormats.h>
#include <Directory.h>
#include <Entry.h>
#include <Debug.h>
#include <File.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <storage/FindDirectory.h>
#include <String.h>
#include "RadeonAddOn.h"
#include "RadeonProducer.h"
#define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
CRadeonPlug::CRadeonPlug( CRadeonAddOn *aaddon, const BPath &adev_path, int aid )
: addon( aaddon ), dev_path( adev_path ), id( aid ), node( NULL )
{
fFlavorInfo.name = const_cast<char *>("Radeon In");
fFlavorInfo.info = const_cast<char *>("Radeon Video In Media Node");
fFlavorInfo.kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT;
fFlavorInfo.flavor_flags = 0;
fFlavorInfo.internal_id = aid;
fFlavorInfo.possible_count = 1;
fFlavorInfo.in_format_count = 0;
fFlavorInfo.in_format_flags = 0;
fFlavorInfo.in_formats = NULL;
fFlavorInfo.out_format_count = 4;
//fFlavorInfo.out_format_count = 1;
fFlavorInfo.out_format_flags = 0;
fMediaFormat[0].type = B_MEDIA_RAW_VIDEO;
fMediaFormat[0].u.raw_video = media_raw_video_format::wildcard;
fMediaFormat[0].u.raw_video.interlace = 1;
fMediaFormat[0].u.raw_video.display.format = B_RGB32;
fMediaFormat[1].type = B_MEDIA_RAW_VIDEO;
fMediaFormat[1].u.raw_video = media_raw_video_format::wildcard;
fMediaFormat[1].u.raw_video.interlace = 1;
fMediaFormat[1].u.raw_video.display.format = B_RGB16;
fMediaFormat[2].type = B_MEDIA_RAW_VIDEO;
fMediaFormat[2].u.raw_video = media_raw_video_format::wildcard;
fMediaFormat[2].u.raw_video.interlace = 1;
fMediaFormat[2].u.raw_video.display.format = B_RGB15;
fMediaFormat[3].type = B_MEDIA_RAW_VIDEO;
fMediaFormat[3].u.raw_video = media_raw_video_format::wildcard;
fMediaFormat[3].u.raw_video.interlace = 1;
fMediaFormat[3].u.raw_video.display.format = B_YCbCr422;
/*fMediaFormat[0].type = B_MEDIA_RAW_VIDEO;
fMediaFormat[0].u.raw_video = media_raw_video_format::wildcard;
fMediaFormat[0].u.raw_video.interlace = 1;
fMediaFormat[0].u.raw_video.display.format = B_YCbCr422;*/
fFlavorInfo.out_formats = fMediaFormat;
readSettings();
}
BPath
CRadeonPlug::getSettingsPath()
{
BPath path;
if( find_directory( B_USER_CONFIG_DIRECTORY, &path ) != B_OK )
return BPath();
path.Append( "settings/Media/RadeonIn" );
create_directory( path.Path(), 755 );
BString id_string;
id_string << "settings" << id;
path.Append( id_string.String() );
return path;
}
void
CRadeonPlug::writeSettings( BMessage *new_settings )
{
BMessage cur_settings;
// if new_settings are provided, use them; else, ask node for settings
// (needed during shutdown where node cannot reply anymore)
if( new_settings != NULL ) {
cur_settings = *new_settings;
} else {
if( node == NULL )
return;
if( addon->GetConfigurationFor( node, &cur_settings ) != B_OK )
return;
}
BMallocIO old_settings_flat, new_settings_flat;
settings.Flatten( &old_settings_flat );
cur_settings.Flatten( &new_settings_flat );
if( old_settings_flat.BufferLength() == new_settings_flat.BufferLength() &&
memcmp( old_settings_flat.Buffer(), new_settings_flat.Buffer(), old_settings_flat.BufferLength() ) == 0 )
return;
settings = cur_settings;
BPath settings_path = getSettingsPath();
BFile file( settings_path.Path(), B_WRITE_ONLY | B_CREATE_FILE );
settings.Flatten( &file );
}
void
CRadeonPlug::readSettings()
{
BPath settings_path = getSettingsPath();
BFile file( settings_path.Path(), B_READ_ONLY );
settings.Unflatten( &file );
}
CRadeonAddOn::CRadeonAddOn(image_id imid)
: BMediaAddOn(imid),
settings_thread( -1 ), settings_thread_sem( -1 )
{
DPRINT(("CRadeonAddOn::CRadeonAddOn()\n"));
fInitStatus = B_NO_INIT;
if( RecursiveScan( "/dev/video/radeon" ) != B_OK )
return;
if( (settings_thread_sem = create_sem( 0, "Radeon In settings" )) < 0 )
return;
if( INIT_BEN( plug_lock, "Radeon device list" ) < 0 )
return;
if( (settings_thread = spawn_thread(
settings_writer, "Radeon In settings", B_LOW_PRIORITY, this )) < 0 )
return;
resume_thread( settings_thread );
fInitStatus = B_OK;
}
CRadeonAddOn::~CRadeonAddOn()
{
status_t dummy;
DPRINT(("CRadeonAddOn::~CRadeonAddOn()\n"));
release_sem( settings_thread_sem );
wait_for_thread( settings_thread, &dummy );
delete_sem( settings_thread_sem );
for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
delete plug;
}
DELETE_BEN( plug_lock );
}
status_t
CRadeonAddOn::InitCheck(const char **out_failure_text)
{
DPRINT(("CRadeonAddOn::InitCheck()\n"));
if (fInitStatus < B_OK) {
*out_failure_text = "Unknown error";
return fInitStatus;
}
return B_OK;
}
int32
CRadeonAddOn::settings_writer( void *param )
{
((CRadeonAddOn *)param)->settingsWriter();
return B_OK;
}
void
CRadeonAddOn::writeSettings()
{
ACQUIRE_BEN( plug_lock );
for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
plug->writeSettings( NULL );
}
RELEASE_BEN( plug_lock );
}
void
CRadeonAddOn::settingsWriter()
{
while( acquire_sem_etc( settings_thread_sem, 1, B_RELATIVE_TIMEOUT, 10000000 ) == B_TIMED_OUT ) {
writeSettings();
}
}
void
CRadeonAddOn::UnregisterNode( BMediaNode *node, BMessage *settings )
{
ACQUIRE_BEN( plug_lock );
for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
if( plug->getNode() == node ) {
// write last settings, so they don't get lost
plug->writeSettings( settings );
plug->setNode( NULL );
break;
}
}
RELEASE_BEN( plug_lock );
}
int32
CRadeonAddOn::CountFlavors()
{
DPRINT(("CRadeonAddOn::CountFlavors()\n"));
if (fInitStatus < B_OK)
return fInitStatus;
return fDevices.CountItems();
}
/*
* The pointer to the flavor received only needs to be valid between
* successive calls to BCRadeonAddOn::GetFlavorAt().
*/
status_t
CRadeonAddOn::GetFlavorAt(int32 n, const flavor_info **out_info)
{
DPRINT(("CRadeonAddOn::GetFlavorAt()\n"));
if (fInitStatus < B_OK)
return fInitStatus;
if (n < 0 || n >= fDevices.CountItems() )
return B_BAD_INDEX;
/* Return the flavor defined in the constructor */
*out_info = ((CRadeonPlug *)fDevices.ItemAt(n))->getFlavorInfo();
return B_OK;
}
BMediaNode *
CRadeonAddOn::InstantiateNodeFor(
const flavor_info *info, BMessage *config, status_t *out_error)
{
DPRINT(("CRadeonAddOn::InstantiateNodeFor()\n"));
CRadeonProducer *node;
if (fInitStatus < B_OK)
return NULL;
if (info->internal_id < 0 || info->internal_id >= fDevices.CountItems())
return NULL;
CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt( info->internal_id );
ACQUIRE_BEN( plug_lock );
if( plug->getNode() != NULL ) {
*out_error = B_BUSY;
node = NULL;
} else {
BMessage single_settings;
// under R5, configuration is always an empty message, so we need to
// get our own configuration
if( config == NULL || 1 )
config = plug->getSettings();
node = new CRadeonProducer( this, plug->getName(),
plug->getDeviceName(), info->internal_id, config );
if (node && (node->InitCheck() < B_OK)) {
*out_error = node->InitCheck();
delete node;
node = NULL;
}
}
plug->setNode( node );
RELEASE_BEN( plug_lock );
return node;
}
status_t CRadeonAddOn::GetConfigurationFor(
BMediaNode *your_node,
BMessage *into_message )
{
port_id reply_port;
CRadeonProducer::configuration_msg msg;
status_t res;
reply_port = create_port( 1, "GetConfiguration Reply" );
if( reply_port < 0 )
return reply_port;
msg.reply_port = reply_port;
res = write_port_etc( your_node->ControlPort(), CRadeonProducer::C_GET_CONFIGURATION,
&msg, sizeof( msg ), B_TIMEOUT, 10000000 );
if( res == B_OK ) {
ssize_t reply_size;
CRadeonProducer::configuration_msg_reply *reply;
int32 code;
reply_size = port_buffer_size_etc( reply_port, B_TIMEOUT, 10000000 );
if( reply_size < 0 )
res = reply_size;
else {
reply = (CRadeonProducer::configuration_msg_reply *)malloc( reply_size );
res = read_port( reply_port, &code, reply, reply_size );
if( res == reply_size ) {
if( code != CRadeonProducer::C_GET_CONFIGURATION_REPLY )
res = B_ERROR;
else {
res = reply->res;
if( res == B_OK )
res = into_message->Unflatten( &reply->config );
}
}
free( reply );
}
}
delete_port( reply_port );
return res;
}
status_t
CRadeonAddOn::RecursiveScan(const char* rootPath, BEntry *rootEntry = NULL)
{
BDirectory root;
if( rootEntry != NULL )
root.SetTo( rootEntry );
else if( rootPath != NULL ) {
root.SetTo( rootPath );
} else {
PRINT(("Error in MultiAudioAddOn::RecursiveScan null params\n"));
return B_ERROR;
}
BEntry entry;
int cur_id = 0;
while( root.GetNextEntry( &entry ) > B_ERROR ) {
if(entry.IsDirectory()) {
RecursiveScan( rootPath, &entry );
} else {
BPath path;
entry.GetPath(&path);
CRadeon device( path.Path() );
if( device.InitCheck() != B_OK)
continue;
CVIPPort vip_port( device );
// if there is a Rage Theatre, then there should be Video-In
if( vip_port.InitCheck() == B_OK &&
vip_port.FindVIPDevice(
(C_THEATER_VIP_VENDOR_ID << 0) |
(C_THEATER_VIP_DEVICE_ID << 16)) >= 0 )
{
fDevices.AddItem( new CRadeonPlug( this, path, cur_id++ ));
}
}
}
return B_OK;
}
BMediaAddOn *
make_media_addon(image_id imid)
{
return new CRadeonAddOn(imid);
}
@@ -0,0 +1,99 @@
/******************************************************************************
/
/ File: RadeonAddOn.h
/
/ Description: ATI Radeon Video Capture Media AddOn for BeOS.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __RADEON_ADDON_H__
#define __RADEON_ADDON_H__
#include <media/MediaAddOn.h>
#include <Path.h>
#include "benaphore.h"
#define TOUCH(x) ((void)(x))
extern "C" _EXPORT BMediaAddOn *make_media_addon(image_id you);
class CRadeonAddOn;
// descriptor of a possible Radeon node
class CRadeonPlug {
public:
CRadeonPlug( CRadeonAddOn *addon, const BPath &dev_path, int id );
~CRadeonPlug() {}
const char *getName() { return fFlavorInfo.name; }
const char *getDeviceName() { return dev_path.Path(); }
const char *getDeviceShortName() { return dev_path.Leaf(); }
flavor_info *getFlavorInfo() { return &fFlavorInfo; }
BMediaNode *getNode() { return node; }
void setNode( BMediaNode *anode ) { node = anode; }
BMessage *getSettings() { return &settings; }
void writeSettings( BMessage *new_settings );
private:
CRadeonAddOn *addon; // (global) addon (only needed for GetConfiguration())
BPath dev_path; // path of device driver
int id; // id of plug
flavor_info fFlavorInfo; // flavor of plug (contains unique id)
BMediaNode *node; // active node (or NULL)
BMessage settings; // settings for this node
media_format fMediaFormat[4];
void readSettings();
BPath getSettingsPath();
};
class CRadeonAddOn : public BMediaAddOn
{
public:
CRadeonAddOn(image_id imid);
virtual ~CRadeonAddOn();
virtual status_t InitCheck(const char **out_failure_text);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(int32 n, const flavor_info ** out_info);
virtual BMediaNode *InstantiateNodeFor(
const flavor_info * info,
BMessage * config,
status_t * out_error);
virtual status_t SaveConfigInfo(BMediaNode *node, BMessage *message)
{ TOUCH(node); TOUCH(message); return B_OK; }
virtual bool WantsAutoStart() { return false; }
virtual status_t AutoStart(int in_count, BMediaNode **out_node,
int32 *out_internal_id, bool *out_has_more)
{ TOUCH(in_count); TOUCH(out_node);
TOUCH(out_internal_id); TOUCH(out_has_more);
return B_ERROR; }
virtual status_t GetConfigurationFor(
BMediaNode *your_node,
BMessage *into_message );
// private methods
void UnregisterNode( BMediaNode *node, BMessage *settings );
private:
status_t fInitStatus;
BList fDevices; // list of BPath of found devices
thread_id settings_thread;
sem_id settings_thread_sem;
benaphore plug_lock;
BMessage settings;
status_t RecursiveScan( const char* rootPath, BEntry *rootEntry = NULL );
static int32 settings_writer( void *param );
void settingsWriter();
void writeSettings();
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,241 @@
/******************************************************************************
/
/ File: RadeonProducer.h
/
/ Description: ATI Radeon Video Producer media node.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __RADEON_PRODUCER_H__
#define __RADEON_PRODUCER_H__
#include <kernel/OS.h>
#include <media/BufferProducer.h>
#include <media/Controllable.h>
#include <media/MediaDefs.h>
#include <media/MediaEventLooper.h>
#include <media/MediaNode.h>
#include <support/Locker.h>
#include "VideoIn.h"
class CRadeonAddOn;
class CRadeonProducer :
public virtual BMediaEventLooper,
public virtual BBufferProducer,
public virtual BControllable
{
public:
CRadeonProducer(
CRadeonAddOn *addon, const char *name, const char *device_name,
int32 internal_id, BMessage *config );
virtual ~CRadeonProducer();
void setupWeb();
virtual status_t InitCheck() const { return fInitStatus; }
/* BMediaNode */
public:
virtual port_id ControlPort() const;
virtual BMediaAddOn *AddOn(int32 * internal_id) const;
virtual status_t HandleMessage(int32 message, const void *data,
size_t size);
protected:
virtual void Preroll();
virtual void SetTimeSource(BTimeSource * time_source);
virtual status_t RequestCompleted(const media_request_info & info);
/* BMediaEventLooper */
protected:
virtual void NodeRegistered();
virtual void Start(bigtime_t performance_time);
virtual void Stop(bigtime_t performance_time, bool immediate);
virtual void Seek(bigtime_t media_time, bigtime_t performance_time);
virtual void TimeWarp(bigtime_t at_real_time,
bigtime_t to_performance_time);
virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie);
virtual void SetRunMode(run_mode mode);
virtual void HandleEvent(const media_timed_event *event,
bigtime_t lateness, bool realTimeEvent = false);
virtual void CleanUpEvent(const media_timed_event *event);
virtual bigtime_t OfflineTime();
virtual void ControlLoop();
virtual status_t DeleteHook(BMediaNode * node);
/* BBufferProducer */
protected:
virtual status_t FormatSuggestionRequested(media_type type, int32 quality,
media_format * format);
virtual status_t FormatProposal(const media_source &output,
media_format *format);
virtual status_t FormatChangeRequested(const media_source &source,
const media_destination &destination,
media_format *io_format, int32 *_deprecated_);
virtual status_t GetNextOutput(int32 * cookie, media_output * out_output);
virtual status_t DisposeOutputCookie(int32 cookie);
virtual status_t SetBufferGroup(const media_source &for_source,
BBufferGroup * group);
virtual status_t VideoClippingChanged(const media_source &for_source,
int16 num_shorts, int16 *clip_data,
const media_video_display_info &display,
int32 * _deprecated_);
virtual status_t GetLatency(bigtime_t * out_latency);
virtual status_t PrepareToConnect(const media_source &what,
const media_destination &where,
media_format *format,
media_source *out_source, char *out_name);
virtual void Connect(status_t error, const media_source &source,
const media_destination &destination,
const media_format & format, char *io_name);
virtual void Disconnect(const media_source & what,
const media_destination & where);
virtual void LateNoticeReceived(const media_source & what,
bigtime_t how_much, bigtime_t performance_time);
virtual void EnableOutput(const media_source & what, bool enabled,
int32 * _deprecated_);
virtual status_t SetPlayRate(int32 numer,int32 denom);
virtual void AdditionalBufferRequested(const media_source & source,
media_buffer_id prev_buffer, bigtime_t prev_time,
const media_seek_tag * prev_tag);
virtual void LatencyChanged(const media_source & source,
const media_destination & destination,
bigtime_t new_latency, uint32 flags);
/* BControllable */
protected:
virtual status_t GetParameterValue(int32 id, bigtime_t *last_change,
void *value, size_t *size);
virtual void SetParameterValue(int32 id, bigtime_t when,
const void *value, size_t size);
virtual status_t StartControlPanel(BMessenger *out_messenger);
public:
enum {
C_GET_CONFIGURATION = BTimedEventQueue::B_USER_EVENT,
C_GET_CONFIGURATION_REPLY
};
struct configuration_msg {
port_id reply_port;
};
struct configuration_msg_reply {
status_t res;
size_t config_size;
char config;
};
/* state */
private:
void HandleStart(bigtime_t performance_time);
void HandleStop();
void HandleTimeWarp(bigtime_t performance_time);
void HandleSeek(bigtime_t performance_time);
void HandleHardware();
// home-brewed extension
status_t GetConfiguration( BMessage *out );
CVideoIn fVideoIn;
status_t fInitStatus;
int32 fInternalID;
CRadeonAddOn *fAddOn;
BBufferGroup *fBufferGroup;
//BBufferGroup *fUsedBufferGroup;
static int32 _frame_generator_(void *data);
int32 FrameGenerator();
/* The remaining variables should be declared volatile, but they
* are not here to improve the legibility of the sample code. */
//uint32 fFrame;
uint32 fFieldSequenceBase;
//bigtime_t fPerformanceTimeBase;
bigtime_t fProcessingLatency;
media_output fOutput;
//media_raw_video_format fConnectedFormat;
//bool fConnected;
bool fEnabled;
// use fixed names as they are used in settings file
enum EOptions {
P_SOURCE = 'VSRC',
P_AUDIO_SOURCE = 'ASRC',
P_AUDIO_FORMAT = 'AFMT',
P_VOLUME = 'VOL ',
P_STANDARD = 'TVST',
P_MODE = 'CMOD',
P_FORMAT = 'VFMT',
P_RESOLUTION = 'RES ',
P_TUNER = 'TUNR',
P_BRIGHTNESS = 'BRGT',
P_CONTRAST = 'CONT',
P_SATURATION = 'SATU',
P_HUE = 'HUE ',
P_SHARPNESS = 'SHRP'
};
enum { C_RESOLUTION_MAX = 6 };
enum { C_CHANNEL_MAX = 125 };
int32 fSource;
int32 fStandard;
int32 fMode;
int32 fCurMode; // mode, overwritten by application
int32 fFormat;
int32 fResolution;
int32 fTuner;
int32 fBrightness;
int32 fContrast;
int32 fSaturation;
int32 fHue;
int32 fSharpness;
bigtime_t fSourceLastChange;
bigtime_t fStandardLastChange;
bigtime_t fModeLastChange;
bigtime_t fFormatLastChange;
bigtime_t fResolutionLastChange;
bigtime_t fTunerLastChange;
bigtime_t fBrightnessLastChange;
bigtime_t fContrastLastChange;
bigtime_t fSaturationLastChange;
bigtime_t fHueLastChange;
bigtime_t fSharpnessLastChange;
status_t AddInt32(
BMessage *msg, EOptions option, int32 value );
status_t FindInt32(
BMessage *config, EOptions option, int32 min_value, int32 max_value,
int32 default_value, int32 *value );
// format negotiation helpers
status_t verifySetMode( media_format *format );
int32 extractCaptureMode( const media_format *format );
status_t verifySetPixelAspect( media_format *format );
status_t verifyActiveRange( media_format *format );
void setActiveRange( media_format *format );
status_t verifyOrientation( media_format *format );
void setOrientation( media_format *format );
status_t verifyPixelFormat( media_format *format );
void setPixelFormat( media_format *format );
status_t verifySetSize( media_format *format, int32 mode, bool set_bytes_per_row );
status_t verifyFormatOffsets( media_format *format );
void setFormatOffsets( media_format *format );
status_t verifyFormatFlags( media_format *format );
void setFormatFlags( media_format *format );
status_t finalizeFormat( media_format *format );
void startCapturing();
void captureField( bigtime_t *capture_time );
void setDefaultBufferGroup();
void instantFormatChange( media_format *new_format );
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,135 @@
/******************************************************************************
/
/ File: Theater.h
/
/ Description: ATI Rage Theater Video Decoder interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __THEATER_H__
#define __THEATER_H__
#include "Radeon.h"
#include "VIPPort.h"
enum theater_identifier {
C_THEATER_VIP_VENDOR_ID = 0x1002,
C_THEATER_VIP_DEVICE_ID = 0x4d54
};
enum theater_standard {
// TK: rearranged to match spec order
C_THEATER_NTSC = 0,
C_THEATER_NTSC_JAPAN = 1,
C_THEATER_NTSC_443 = 2,
C_THEATER_PAL_M = 3,
C_THEATER_PAL_N = 4,
C_THEATER_PAL_NC = 5,
C_THEATER_PAL_BDGHI = 6,
C_THEATER_PAL_60 = 7,
C_THEATER_SECAM = 8
};
enum theater_source {
C_THEATER_TUNER = 0,
C_THEATER_COMPOSITE = 1,
C_THEATER_SVIDEO = 2
};
class CTheater {
public:
CTheater(CRadeon & radeon);
~CTheater();
status_t InitCheck() const;
void Reset();
void SetEnable(bool enable, bool vbi);
void SetStandard(theater_standard standard, theater_source source);
void SetSize(int hactive, int vactive);
void SetDeinterlace(bool deinterlace);
void SetSharpness(int sharpness);
void SetBrightness(int brightness);
void SetContrast(int contrast);
void SetSaturation(int saturation);
void SetHue(int hue);
int CurrentLine();
void getActiveRange( theater_standard standard, CRadeonRect &rect );
void getVBIRange( theater_standard standard, CRadeonRect &rect );
void PrintToStream();
private:
void SetClock(theater_standard standard, radeon_video_clock clock);
void SetADC(theater_standard standard, theater_source source);
void SetHSYNC(theater_standard standard);
void WaitHSYNC();
void SetVSYNC(theater_standard standard);
void WaitVSYNC();
void SetSyncGenerator(theater_standard standard);
void SetCombFilter(theater_standard standard, theater_source source);
void SetLuminanceProcessor(theater_standard standard);
void SetLuminanceLevels(theater_standard standard, int brightness, int contrast);
void SetChromaProcessor(theater_standard standard);
void SetChromaLevels(theater_standard standard, int saturation, int hue);
void SetClipWindow(theater_standard standard, bool vbi);
void SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace);
public:
int Register(int index);
int Register(int index, int mask);
void SetRegister(int index, int value);
void SetRegister(int index, int mask, int value);
private:
CVIPPort fPort;
int fDevice;
radeon_video_clock fClock;
int fTunerPort;
int fCompositePort;
int fSVideoPort;
theater_standard fStandard;
theater_source fSource;
int fBrightness;
int fContrast;
int fSaturation;
int fHue;
int fHActive;
int fVActive;
bool fDeinterlace;
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,323 @@
/******************************************************************************
/
/ File: Tuner.cpp
/
/ Description: Philips Desktop TV Tuners interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <Debug.h>
#include "Tuner.h"
enum tuner_control_bits {
CHANGE_PUMP = 0x40, /* change pump settings */
CHANGE_PUMP_FAST = 0x00, /* for fast tuning */
CHANGE_PUMP_SLOW = 0x40, /* for moderate speed tuning */
TEST_MODE = 0x38, /* test mode settings */
TEST_MODE_NORMAL = 0x08, /* for normal operation */
RATIO_SELECT = 0x06, /* ratio select */
RATIO_SELECT_FAST = 0x00, /* fast picture search */
RATIO_SELECT_SLOW = 0x02, /* slow picture search */
RATIO_SELECT_NORMAL = 0x06, /* normal picture search */
OS_MODE = 0x01, /* PLL disabling */
OS_MODE_NORMAL = 0x00, /* for normal operation */
OS_MODE_SWITCH = 0x01 /* change pump to high impedance */
};
enum tuner_status_bits {
STB_POR = 0x80, /* power on reset */
STB_FL = 0x40, /* in-lock flag */
STB_INF = 0x38, /* digital information */
STB_ADC = 0x07 /* A/D converter */
};
/*****************************************************************************
/
/ Tuner Parameters and Frequencies for TV Antenna and Cable Channels
/
******************************************************************************/
static const int kBandsPerTuner = 5;
static const struct {
tuner_type brand;
const char* name;
struct {
int pll;
float minFrequency, maxFrequency;
} bands[kBandsPerTuner];
} kTunerTable[] = {
/* Philips FI1236 NTSC M/N */
{ C_TUNER_FI1236, "FI1236 NTSC",
{ { 0xa2, 54.00, 157.25 },
{ 0x94, 162.00, 451.25 },
{ 0x34, 451.25, 463.25 },
{ 0x31, 463.25, 801.25 },
{ 0x00, 0.00, 0.00 } } },
/* Philips FI1236J NTSC Japan */
{ C_TUNER_FI1236J, "FI1236J NTSC Japan",
{ { 0xa2, 54.00, 157.25 },
{ 0x94, 162.00, 451.25 },
{ 0x34, 451.25, 463.25 },
{ 0x31, 463.25, 801.25 },
{ 0x00, 0.00, 0.00 } } },
/* Philips FI1236MK2 NTSC M/N */
{ C_TUNER_FI1236MK2, "FI1236MK2 NTSC",
{ { 0xa0, 55.25, 160.00 },
{ 0x90, 160.00, 454.00 },
{ 0x30, 454.00, 855.25 },
{ 0x00, 0.00, 0.00 },
{ 0x00, 0.00, 0.00 } } },
/* Philips FI1216 PAL B/G */
{ C_TUNER_FI1216, "FI1216 PAL",
{ { 0xa2, 45.00, 140.25 },
{ 0xa4, 140.25, 168.25 },
{ 0x94, 168.25, 447.25 },
{ 0x34, 447.25, 463.25 },
{ 0x31, 463.25, 855.25 } } },
/* Philips FI1216MK2 PAL B/G */
{ C_TUNER_FI1216MK2, "FI1216MK2 PAL",
{ { 0xa0, 48.25, 170.00 },
{ 0x90, 170.00, 450.00 },
{ 0x30, 450.00, 855.25 },
{ 0x00, 0.00, 0.00 },
{ 0x00, 0.00, 0.00 } } },
/* Philips FI1216MF PAL B/G, SECAM L/L' */
{ C_TUNER_FI1216MF, "FI1216MF PAL/SECAM",
{ { 0xa1, 45.00, 168.25 },
{ 0x91, 168.25, 447.25 },
{ 0x31, 447.25, 855.25 },
{ 0x00, 0.00, 0.00 },
{ 0x00, 0.00, 0.00 } } },
/* Philips FI1246 PAL I */
{ C_TUNER_FI1246, "FI1246 PAL I",
{ { 0xa2, 45.00, 140.25 },
{ 0xa4, 140.25, 168.25 },
{ 0x94, 168.25, 447.25 },
{ 0x34, 447.25, 463.25 },
{ 0x31, 463.25, 855.25 } } },
/* Philips FI1256 SECAM D/K */
{ C_TUNER_FI1256, "FI1256 SECAM",
{ { 0xa0, 48.25, 168.25 },
{ 0x90, 175.25, 455.25 },
{ 0x30, 463.25, 863.25 },
{ 0x00, 0.00, 0.00 },
{ 0x00, 0.00, 0.00 } } },
/* Temic FN5AL PAL I/B/G/DK, SECAM DK */
{ C_TUNER_TEMIC_FN5AL_PAL, "Temic FN5AL PAL",
{ { 0xa2, 45.00, 140.25 },
{ 0xa4, 140.25, 168.25 },
{ 0x94, 168.25, 447.25 },
{ 0x31, 447.25, 855.25 },
{ 0x00, 0.00, 0.00 } } },
/* Temic FN5AL PAL I/B/G/DK, SECAM DK */
{ C_TUNER_TEMIC_FN5AL_SECAM, "Temic FN5AL SECAM",
{ { 0xa0, 48.25, 168.25 },
{ 0x90, 175.25, 455.25 },
{ 0x30, 463.25, 863.25 },
{ 0x00, 0.00, 0.00 },
{ 0x00, 0.00, 0.00 } } } };
static const int kNumTuners = sizeof(kTunerTable) / sizeof(kTunerTable[0]);
CTuner::CTuner(CI2CPort & port)
: fPort(port),
fType(C_TUNER_NONE),
fAddress(0xC6),
fDivider(0)
{
PRINT(("CTuner::CTuner()\n"));
if( fPort.InitCheck() == B_OK ) {
radeon_video_tuner tuner;
radeon_video_decoder video;
radeon_video_clock clock;
int dummy;
fPort.Radeon().GetMMParameters(tuner, video, clock, dummy, dummy, dummy);
switch (tuner) {
case C_RADEON_NO_TUNER:
fType = C_TUNER_NONE;
break;
case C_RADEON_FI1236_MK1_NTSC:
fType = C_TUNER_FI1236;
break;
case C_RADEON_FI1236_MK2_NTSC_JAPAN:
fType = C_TUNER_FI1236J;
break;
case C_RADEON_FI1216_MK2_PAL_BG:
fType = C_TUNER_FI1216;
break;
case C_RADEON_FI1246_MK2_PAL_I:
fType = C_TUNER_FI1246;
break;
case C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L:
fType = C_TUNER_FI1216MF;
break;
case C_RADEON_FI1236_MK2_NTSC:
fType = C_TUNER_FI1236MK2;
break;
case C_RADEON_FI1256_MK2_SECAM_DK:
fType = C_TUNER_FI1256;
break;
case C_RADEON_FI1216_MK2_PAL_BG_SECAM_L:
fType = C_TUNER_FI1216MK2;
break;
case C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK:
fType = C_TUNER_TEMIC_FN5AL_PAL;
break;
default:
fType = C_TUNER_FI1236;
break;
}
for (fAddress = 0xc0; fAddress <= 0xc6; fAddress += 0x02) {
if (fPort.Probe(fAddress)) {
PRINT(("CTuner::CTuner() - TV Tuner found at I2C port 0x%02x\n", fAddress));
break;
}
}
}
if( InitCheck() != B_OK )
PRINT(("CTuner::CTuner() - TV Tuner not found!\n"));
}
CTuner::~CTuner()
{
PRINT(("CTuner::~CTuner()\n"));
}
status_t CTuner::InitCheck() const
{
return (fType != C_TUNER_NONE && fAddress >= 0xc0 && fAddress <= 0xc6) ?
B_OK : B_ERROR;
}
bool CTuner::SetFrequency(float frequency, float picture)
{
//PRINT(("CTuner::SetFrequency(%g, %g)\n", frequency, picture));
for (int index = 0; index < kNumTuners; index++) {
if (kTunerTable[index].brand == fType) {
for (int band = 0; band < kBandsPerTuner; band++) {
if (frequency >= kTunerTable[index].bands[band].minFrequency &&
frequency <= kTunerTable[index].bands[band].maxFrequency) {
SetParameters(
(int) (16.0 * (frequency + picture)),
CHANGE_PUMP_FAST | RATIO_SELECT_NORMAL |
TEST_MODE_NORMAL | OS_MODE_NORMAL,
kTunerTable[index].bands[band].pll |
((Status() & STB_INF) >> 3));
return true;
}
}
}
}
return false;
}
bool CTuner::SweepFrequency(float frequency, float picture)
{
PRINT(("CTuner::SweepFrequency(%g, %g)\n", frequency, picture));
float centerFrequency = frequency;
/* sweeping down */
do {
SetFrequency(frequency, picture);
for (int timeout = 0; timeout < 10; timeout++) {
snooze(20000);
if (IsLocked())
break;
}
} while (ADC() == 0 &&
(frequency -= 0.5000) > centerFrequency - 3.000);
/* sweeping up */
do {
SetFrequency(frequency, picture);
for (int timeout = 0; timeout < 10; timeout++) {
snooze(20000);
if (IsLocked())
break;
}
} while (ADC() != 0 &&
(frequency += 0.0625) < centerFrequency + 0.500);
return (ADC() == 0);
}
const char * CTuner::Name() const
{
for (int index = 0; index < kNumTuners; index++) {
if (kTunerTable[index].brand == fType)
return kTunerTable[index].name;
}
return 0;
}
tuner_type CTuner::Type() const
{
return fType;
}
bool CTuner::HasSignal(void)
{
return (IsLocked() && ADC() <= 2);
}
int CTuner::Status(void)
{
char buffer[1];
fPort.Read(fAddress, buffer, sizeof(buffer));
return buffer[0] & 0xff;
}
int CTuner::ADC(void)
{
return Status() & STB_ADC;
}
bool CTuner::IsLocked(void)
{
return (Status() & STB_FL) != 0;
}
void CTuner::SetParameters(int divider, int control, int band)
{
char buffer[4];
if (divider > fDivider) {
buffer[0] = (divider >> 8) & 0x7f;
buffer[1] = (divider >> 0) & 0xff;
buffer[2] = (control | 0x80);
buffer[3] = (band & 0xff);
}
else {
buffer[0] = (control | 0x80);
buffer[1] = (band & 0xff);
buffer[2] = (divider >> 8) & 0x7f;
buffer[3] = (divider >> 0) & 0xff;
}
fDivider = divider;
fPort.Write(fAddress, buffer, sizeof(buffer));
}
@@ -0,0 +1,70 @@
/******************************************************************************
/
/ File: Tuner.h
/
/ Description: Philips Desktop TV Tuners interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __TUNER_H__
#define __TUNER_H__
#include "I2CPort.h"
enum tuner_type {
C_TUNER_NONE = 0x1400, /* Unknown */
C_TUNER_FI1236 = 0x1401, /* NTSC M/N */
C_TUNER_FI1236J = 0x1402, /* NTSC Japan */
C_TUNER_FI1236MK2 = 0x1403, /* NTSC M/N */
C_TUNER_FI1216 = 0x1404, /* PAL B/G */
C_TUNER_FI1216MK2 = 0x1405, /* PAL B/G */
C_TUNER_FI1216MF = 0x1406, /* PAL B/G, SECAM L/L' */
C_TUNER_FI1246 = 0x1407, /* PAL I */
C_TUNER_FI1256 = 0x1408, /* SECAM D/K */
C_TUNER_TEMIC_FN5AL_PAL = 0x1409, /* PAL I/B/G/DK */
C_TUNER_TEMIC_FN5AL_SECAM = 0x140a /* SECAM DK */
};
enum tuner_picture_carrier {
C_TUNER_NTSC_PICTURE_CARRIER = 4575,
C_TUNER_PAL_PICTURE_CARRIER = 3890,
C_TUNER_SECAM_PICTURE_CARRIER = 3890
};
class CTuner {
public:
CTuner(CI2CPort & port);
~CTuner();
status_t InitCheck() const;
const char * Name() const;
tuner_type Type() const;
bool SetFrequency(float frequency, float picture);
bool SweepFrequency(float frequency, float picture);
bool HasSignal(void);
int Status();
bool IsLocked();
int ADC();
private:
void SetParameters(int divider, int control, int band);
private:
CI2CPort & fPort;
tuner_type fType;
int fAddress;
int fDivider;
};
#endif
@@ -0,0 +1,33 @@
/******************************************************************************
/
/ File: VIP.cpp
/
/ Description: ATI Radeon Video Input Port (VIP) interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <Debug.h>
#include "VIPPort.h"
CVIPPort::CVIPPort(CRadeon & radeon)
: fRadeon(radeon)
{
PRINT(("CVIPPort::CVIPPort()\n"));
}
CVIPPort::~CVIPPort()
{
PRINT(("CVIPPort::~CVIPPort()\n"));
}
status_t CVIPPort::InitCheck() const
{
return fRadeon.InitCheck();
}
CRadeon & CVIPPort::Radeon()
{
return fRadeon;
}
@@ -0,0 +1,69 @@
/******************************************************************************
/
/ File: VIP.h
/
/ Description: ATI Radeon Video Input Port (VIP) interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __VIP_PORT_H__
#define __VIP_PORT_H__
#include "Radeon.h"
enum vip_port_device {
C_VIP_PORT_DEVICE_0 = 0,
C_VIP_PORT_DEVICE_1 = 1,
C_VIP_PORT_DEVICE_2 = 2,
C_VIP_PORT_DEVICE_3 = 3
};
enum vip_port_register {
C_VIP_VENDOR_DEVICE_ID = 0x0000,
C_VIP_VENDOR_ID = BITS(15:0),
C_VIP_DEVICE_ID = BITS(31:16),
C_VIP_SUB_VENDOR_DEVICE_ID = 0x0004,
C_VIP_SUB_VENDOR_ID = BITS(15:0),
C_VIP_SUB_DEVICE_ID = BITS(31:16),
C_VIP_COMMAND_STATUS = 0x0008,
C_VIP_POWER_ST = BITS(1:0),
C_VIP_XHOST_ON = BITS(2:2),
C_VIP_P1_SUPPORT = BITS(16:16),
C_VIP_P2_SUPPORT = BITS(17:17),
C_VIP_HOST_CAP = BITS(19:18),
C_VIP_REVISION_ID = 0x000c,
C_VIP_REVISION_ID_MASK = BITS(15:0)
};
class CVIPPort {
public:
CVIPPort(CRadeon & radeon);
~CVIPPort();
status_t InitCheck() const;
CRadeon & Radeon();
int Register(int device, int address) {
return fRadeon.VIPRegister( device, address );
}
void SetRegister(int device, int address, int value) {
fRadeon.SetVIPRegister( device, address, value );
}
int FindVIPDevice( uint32 device_id ) {
return fRadeon.FindVIPDevice( device_id );
}
private:
CRadeon & fRadeon;
};
#endif
@@ -0,0 +1,453 @@
/******************************************************************************
/
/ File: VideoIn.cpp
/
/ Description: High-Level ATI Radeon Video Capture Interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#include <Debug.h>
#include "VideoIn.h"
#include <memory.h>
static const theater_standard kStandard[] = {
C_THEATER_NTSC,
C_THEATER_NTSC_JAPAN,
C_THEATER_NTSC_443,
C_THEATER_PAL_M,
C_THEATER_PAL_BDGHI,
C_THEATER_PAL_N,
C_THEATER_PAL_60,
C_THEATER_PAL_NC,
C_THEATER_SECAM,
// C_THEATER_NTSC_RAW
};
static const theater_source kSource[] = {
C_THEATER_TUNER,
C_THEATER_COMPOSITE,
C_THEATER_SVIDEO
};
static const capture_buffer_mode kMode[] = {
C_RADEON_CAPTURE_FIELD_DOUBLE,
C_RADEON_CAPTURE_BOB_DOUBLE,
C_RADEON_CAPTURE_WEAVE_DOUBLE
};
static const struct {
struct {
int width, height;
} total;
struct {
int left, top;
int width, height;
} active;
struct {
int left, top;
int width, height;
} vbi;
} kTiming[] = {
{ { 910, 525 }, { 112, 37, 755, 480 }, { 73, 13, 798, 20 } }, // NTSC-M
{ { 910, 525 }, { 112, 37, 755, 480 }, { 73, 13, 798, 24 } }, // NTSC-Japan
{ { 1042, 525 }, { 126, 37, 940, 480 }, { 73, 13, 798, 24 } }, // NTSC-443
{ { 910, 525 }, { 103, 37, 764, 480 }, { 73, 13, 798, 24 } }, // PAL-M
{ { 1135, 625 }, { 154, 35, 928, 576 }, { 132, 11, 924, 24 } }, // PAL-BDGHI
{ { 1135, 625 }, { 154, 35, 928, 576 }, { 132, 11, 924, 24 } }, // PAL-N
{ { 1125, 625 }, { 132, 37, 736, 480 }, { 100, 13, 770, 26 } }, // PAL-60
{ { 910, 625 }, { 125, 35, 957, 576 }, { 132, 11, 924, 24 } }, // PAL-NC
{ { 1135, 625 }, { 149, 35, 933, 576 }, { 132, 11, 924, 24 } }, // SECAM
{ { 910, 525 }, { 112, 37, 755, 480 }, { 73, 13, 798, 22 } } // NTSC-Raw
};
CVideoIn::CVideoIn( const char *dev_name )
: fRadeon( dev_name ),
fCapture(fRadeon),
fI2CPort(fRadeon),
fTheater(fRadeon),
fTuner(fI2CPort),
fSound(fI2CPort),
fBuffer0(0),
fBuffer1(0),
fBuffer0Handle(0),
fBuffer1Handle(0),
convert_buffer( NULL ),
fBufferLength(0),
fBufferBytesPerRow(0),
fBufferSequence(0),
fBufferPeriod(0),
started( false )
{
Trace("CVideoIn::CVideoIn()");
}
CVideoIn::~CVideoIn()
{
Trace("CVideoIn::~CVideoIn()");
FreeBuffers();
}
status_t CVideoIn::InitCheck() const
{
status_t res;
Trace("CVideoIn::InitCheck()");
if( (res = fRadeon.InitCheck()) != B_OK )
return res;
if( (res = fCapture.InitCheck()) != B_OK )
return res;
if( (res = fI2CPort.InitCheck()) != B_OK )
return res;
return fTheater.InitCheck();
}
int CVideoIn::Capabilities() const
{
return (fTuner.InitCheck() == B_OK ? C_VIDEO_IN_HAS_TUNER + C_VIDEO_IN_HAS_COMPOSITE + C_VIDEO_IN_HAS_SVIDEO : 0) +
(fSound.InitCheck() == B_OK ? C_VIDEO_IN_HAS_SOUND : 0);
}
void CVideoIn::Start(video_in_source source, video_in_standard standard,
video_in_capture_mode mode, int width, int height)
{
char buffer[256];
sprintf(buffer, "CVideoIn::Start(%s, %d, %d)",
mode == C_VIDEO_IN_FIELD ? "C_VIDEO_IN_FIELD" :
mode == C_VIDEO_IN_BOB ? "C_VIDEO_IN_BOB" : "C_VIDEO_IN_WEAVE", width, height);
Trace(buffer);
if( started )
Stop();
switch (mode) {
case C_VIDEO_IN_FIELD:
case C_VIDEO_IN_BOB:
width = Clamp(width, 0, kTiming[standard].active.width);
height = Clamp(height, 0, kTiming[standard].active.height / 2);
break;
case C_VIDEO_IN_WEAVE:
width = Clamp(width, 0, kTiming[standard].active.width);
height = Clamp(height, 0, kTiming[standard].active.height);
break;
}
fBufferBytesPerRow = (2 * width + 15) & ~15;
fBufferLength = (fBufferBytesPerRow * height + 15) & ~15;
FreeBuffers();
// TBD:
// no error handling !!!!
fRadeon.AllocateGraphicsMemory(
mt_local,
mode == C_VIDEO_IN_BOB ? 4 * fBufferLength : 2 * fBufferLength,
&fBuffer0, &fBuffer0Handle );
fRadeon.AllocateGraphicsMemory(
mt_local,
mode == C_VIDEO_IN_BOB ? 2 * fBufferLength : 1 * fBufferLength,
&fBuffer1, &fBuffer1Handle );
convert_buffer = malloc( mode == C_VIDEO_IN_BOB ? 4 * fBufferLength : 2 * fBufferLength );
fBufferPeriod = 1000000000LL / getFrameRate( standard );
if( mode == C_VIDEO_IN_BOB )
fBufferPeriod >>= 1;
fTheater.SetStandard(kStandard[standard], kSource[source]);
fTheater.SetSize(width, (mode != C_VIDEO_IN_WEAVE ? 2 * height : height));
fCapture.SetBuffer(C_RADEON_CAPTURE_CCIR656, kMode[mode], fBuffer0, fBuffer1, fBufferLength, fBufferBytesPerRow >> 1);
fCapture.SetClip(0, kTiming[standard].vbi.height, width - 1, kTiming[standard].vbi.height + (mode != C_VIDEO_IN_WEAVE ? height : height >> 1) - 1);
fTheater.SetEnable(true, false);
if( fSound.InitCheck() == B_OK )
fSound.SetEnable(true);
fCapture.SetInterrupts(true);
fCapture.Start();
}
void CVideoIn::Stop()
{
Trace("CVideoIn::Stop()");
if( !started )
return;
fCapture.Stop();
fCapture.SetInterrupts(false);
if( fSound.InitCheck() == B_OK )
fSound.SetEnable(false);
fTheater.SetEnable(false, false);
FreeBuffers();
}
void CVideoIn::FreeBuffers()
{
if( fBuffer0Handle > 0 ) {
fRadeon.FreeGraphicsMemory( mt_local, fBuffer0Handle );
fBuffer0Handle = 0;
}
if( fBuffer1Handle > 0 ) {
fRadeon.FreeGraphicsMemory( mt_local, fBuffer1Handle );
fBuffer1Handle = 0;
}
if( convert_buffer != NULL ) {
free( convert_buffer );
convert_buffer = NULL;
}
}
void CVideoIn::SetBrightness(int brightness)
{
Trace("CVideoIn::SetBrightness()");
fTheater.SetBrightness(brightness);
}
void CVideoIn::SetContrast(int contrast)
{
Trace("CVideoIn::SetContrast()");
fTheater.SetContrast(contrast);
}
void CVideoIn::SetSaturation(int saturation)
{
Trace("CVideoIn::SetSaturation()");
fTheater.SetSaturation(saturation);
}
void CVideoIn::SetHue(int hue)
{
Trace("CVideoIn::SetHue()");
fTheater.SetHue(hue);
}
void CVideoIn::SetSharpness(int sharpness)
{
Trace("CVideoIn::SetSharpness()");
fTheater.SetSharpness(sharpness);
}
void CVideoIn::SetFrequency(float frequency, float picture)
{
Trace("CVideoIn::SetFrequency()");
if (fTuner.Type() != C_TUNER_NONE)
fTuner.SweepFrequency(frequency, picture);
}
float CVideoIn::FrequencyForChannel(int channel, video_in_standard standard)
{
float frequency = 0;
Trace("CVideoIn::FrequencyForChannel()");
if (fTuner.Type() != C_TUNER_NONE) {
switch (standard) {
case C_VIDEO_IN_NTSC:
case C_VIDEO_IN_NTSC_RAW:
// NTSC Cable
if (channel >= 2 && channel <= 6) {
frequency = 55.25 + 6.00 * (channel - 2);
}
else if (channel >= 7 && channel <= 13) {
frequency = 175.25 + 6.00 * (channel - 7);
}
else if (channel >= 14 && channel <= 22) {
frequency = 121.25 + 6.00 * (channel - 14);
}
else if (channel >= 23 && channel <= 36) {
frequency = 217.25 + 6.00 * (channel - 23);
}
else if (channel >= 37 && channel <= 62) {
frequency = 301.25 + 6.00 * (channel - 37);
}
else if (channel >= 63 && channel <= 94) {
frequency = 457.25 + 6.00 * (channel - 63);
}
else if (channel >= 95 && channel <= 99) {
frequency = 91.25 + 6.00 * (channel - 95);
}
else if (channel >= 100 && channel <= 125) {
frequency = 649.25 + 6.00 * (channel - 100);
}
else {
frequency = 0;
}
break;
case C_VIDEO_IN_NTSC_JAPAN:
case C_VIDEO_IN_NTSC_443:
case C_VIDEO_IN_PAL_M:
case C_VIDEO_IN_PAL_BDGHI:
case C_VIDEO_IN_PAL_N:
case C_VIDEO_IN_PAL_60:
case C_VIDEO_IN_PAL_NC:
case C_VIDEO_IN_SECAM:
break;
}
}
return frequency;
}
bool CVideoIn::SetChannel(int channel, video_in_standard standard)
{
Trace("CVideoIn::SetChannel()");
if (fTuner.Type() == C_TUNER_NONE)
return true;
const float frequency = FrequencyForChannel(channel, standard);
switch (standard) {
case C_VIDEO_IN_NTSC:
case C_VIDEO_IN_NTSC_RAW:
return fTuner.SweepFrequency(frequency, C_TUNER_NTSC_PICTURE_CARRIER / 100.0f);
break;
case C_VIDEO_IN_NTSC_JAPAN:
case C_VIDEO_IN_NTSC_443:
case C_VIDEO_IN_PAL_M:
case C_VIDEO_IN_PAL_BDGHI:
case C_VIDEO_IN_PAL_N:
case C_VIDEO_IN_PAL_60:
case C_VIDEO_IN_PAL_NC:
case C_VIDEO_IN_SECAM:
return fTuner.SweepFrequency(frequency, C_TUNER_PAL_PICTURE_CARRIER / 100.0f);
}
return false;
}
int CVideoIn::Capture(color_space colorSpace, void * bits, int bitsLength,
int bytesPerRow, int * sequence, short * number, bigtime_t * when)
{
// Trace("CVideoIn::Capture()");
int mask, counter;
if ((mask = fCapture.WaitInterrupts(sequence, when, fBufferPeriod)) == 0)
return 0;
*number = ((mask & (C_RADEON_CAPTURE_BUF0_INT | C_RADEON_CAPTURE_BUF1_INT)) != 0 ? 0 : 1);
int32 captured_buffer =
((mask & C_RADEON_CAPTURE_BUF0_INT) != 0 ? fBuffer0 :
(mask & C_RADEON_CAPTURE_BUF1_INT) != 0 ? fBuffer1 :
(mask & C_RADEON_CAPTURE_BUF0_EVEN_INT) != 0 ? fBuffer0 + fBufferLength :
(mask & C_RADEON_CAPTURE_BUF1_EVEN_INT) != 0 ? fBuffer1 + fBufferLength : 0);
/*PRINT(("colorSpace:%x, bitsLength: %d, fBufferLength: %d, bytesPerRow: %d, fBufferBytesPerRow: %d\n",
colorSpace, bitsLength, fBufferLength, bytesPerRow, fBufferBytesPerRow ));*/
// always copy into main memory first, even if it must be converted by CPU -
// reading from graphics mem is incredibly slow
if (colorSpace == B_YCbCr422 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) {
PRINT(("%d, %p\n", captured_buffer, bits));
fRadeon.DMACopy( captured_buffer, bits, bitsLength, true, false );
}
else if (colorSpace == B_RGB32 && bitsLength <= 2 * fBufferLength && bytesPerRow == 2 * fBufferBytesPerRow) {
fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false );
#define RGB32
#include "yuv_converter.h"
#undef RGB32
}
else if (colorSpace == B_RGB16 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) {
fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false );
#define RGB16
#include "yuv_converter.h"
#undef RGB16
}
else if (colorSpace == B_RGB15 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) {
fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false );
#define RGB15
#include "yuv_converter.h"
#undef RGB15
}
else if (colorSpace == B_GRAY8 && 2 * bitsLength <= fBufferLength && 2 * bytesPerRow == fBufferBytesPerRow) {
fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false );
static const unsigned short mask[] = {
0x00ff, 0x00ff, 0x00ff, 0x00ff };
asm volatile(
"1:\n"
"movq 0x00(%0),%%mm0\n" // mm0 = Cr2' Y3 Cb2' Y2 Cr0' Y1 Cb0' Y0
"movq 0x08(%0),%%mm1\n" // mm1 = Cr6' Y7 Cb6' Y6 Cr4' Y5 Cb4' Y4
"pand %3,%%mm0\n" // mm0 = 00 Y3 00 Y2 00 Y1 00 Y0
"pand %3,%%mm1\n" // mm1 = 00 Y7 00 Y6 00 Y5 00 Y4
"packuswb %%mm1,%%mm0\n" // mm0 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
"movq %%mm0,(%1)\n" // destination[0] = mm0
"addl $0x10,%0\n" // source += 16
"addl $0x08,%1\n" // destination += 8
"subl $0x08,%2\n"
"jg 1b\n"
"emms\n"
:
: "r" (convert_buffer), "r" (bits), "r" (bitsLength), "m" (mask));
}
else if( colorSpace == B_NO_COLOR_SPACE ) {
// special case: only wait for image but don't copy it
;
}
else {
PRINT(("CVideoIn::Capture() - Bad buffer format\n"));
}
counter = *sequence - fBufferSequence;
fBufferSequence = *sequence;
return counter;
}
void CVideoIn::Trace(const char * message) const
{
PRINT(("\x1b[0;30;34m%s\x1b[0;30;47m\n", message));
}
int32 CVideoIn::getFrameRate( video_in_standard standard )
{
// TODO: I'm not really sure about these values
static const int32 frame_rate[] = {
29976, 29976, 29976, 25000, 25000, 25000, 29976, 25000, 25000, 29976
};
return frame_rate[standard];
}
void CVideoIn::getActiveRange( video_in_standard standard, CRadeonRect &rect )
{
// in theory, we would ask fTheatre;
// in practice, values retrieved from there don't work;
// e.g. for PAL, according to Theatre, VBI height is 38, but you must set up the
// clipping unit to height 24! I have no clue what goes wrong there
rect.SetTo(
kTiming[standard].active.left,
kTiming[standard].active.top,
kTiming[standard].active.left + kTiming[standard].active.width - 1,
kTiming[standard].active.top + kTiming[standard].active.height - 1 );
}
@@ -0,0 +1,144 @@
/******************************************************************************
/
/ File: VideoIn.h
/
/ Description: High-Level ATI Radeon Video Capture Interface.
/
/ Copyright 2001, Carlos Hasan
/
*******************************************************************************/
#ifndef __VIDEO_IN_H__
#define __VIDEO_IN_H__
#include "Radeon.h"
#include "Capture.h"
//#include "Overlay.h"
#include "I2CPort.h"
#include "VIPPort.h"
#include "Tuner.h"
#include "MSP3430.h"
#include "Theater.h"
enum video_in_source {
C_VIDEO_IN_TUNER,
C_VIDEO_IN_COMPOSITE,
C_VIDEO_IN_SVIDEO,
};
enum { C_VIDEO_IN_SOURCE_MAX = 2 };
enum video_in_standard {
C_VIDEO_IN_NTSC,
C_VIDEO_IN_NTSC_JAPAN,
C_VIDEO_IN_NTSC_443,
C_VIDEO_IN_PAL_M,
C_VIDEO_IN_PAL_BDGHI,
C_VIDEO_IN_PAL_N,
C_VIDEO_IN_PAL_60,
C_VIDEO_IN_PAL_NC,
C_VIDEO_IN_SECAM,
C_VIDEO_IN_NTSC_RAW
};
enum { C_VIDEO_IN_STANDARD_MAX = 8 };
enum video_in_capture_mode {
C_VIDEO_IN_FIELD,
C_VIDEO_IN_BOB,
C_VIDEO_IN_WEAVE
};
enum { C_VIDEO_IN_CAPTURE_MODE_MAX = 2 };
enum video_in_resolution {
C_VIDEO_IN_NTSC_SQ_WIDTH = 640,
C_VIDEO_IN_NTSC_SQ_HEIGHT = 480,
C_VIDEO_IN_NTSC_CCIR_WIDTH = 720,
C_VIDEO_IN_NTSC_CCIR_HEIGHT = 480,
C_VIDEO_IN_PAL_SQ_WIDTH = 768,
C_VIDEO_IN_PAL_SQ_HEIGHT = 576,
C_VIDEO_IN_PAL_CCIR_WIDTH = 720,
C_VIDEO_IN_PAL_CCIR_HEIGHT = 576
};
/*enum video_in_frame_rate {
C_VIDEO_IN_NTSC_FRAME_RATE = 29976,
C_VIDEO_IN_PAL_FRAME_RATE = 25000
};*/
enum video_in_capabilities {
C_VIDEO_IN_HAS_SOUND = 1 << 0,
C_VIDEO_IN_HAS_TUNER = 1 << 1,
C_VIDEO_IN_HAS_COMPOSITE = 1 << 2,
C_VIDEO_IN_HAS_SVIDEO = 1 << 3
};
class CVideoIn {
public:
CVideoIn( const char *dev_name );
~CVideoIn();
status_t InitCheck() const;
int Capabilities() const;
public:
void Start(video_in_source source, video_in_standard standard,
video_in_capture_mode mode, int width, int height);
void Stop();
int Capture(color_space colorSpace, void * bits, int bitsLength,
int bytesPerRow, int * sequence, short * number, bigtime_t * when);
public:
void SetBrightness(int brightness);
void SetContrast(int contrast);
void SetSaturation(int saturation);
void SetHue(int hue);
void SetSharpness(int sharpness);
void SetFrequency(float frequency, float picture);
float FrequencyForChannel(int channel, video_in_standard standard);
bool SetChannel(int channel, video_in_standard standard);
int32 getFrameRate( video_in_standard standard );
void getActiveRange( video_in_standard standard, CRadeonRect &rect );
private:
void FreeBuffers();
void Trace(const char * message) const;
private:
CRadeon fRadeon;
CCapture fCapture;
CI2CPort fI2CPort;
CTheater fTheater;
CTuner fTuner;
CMSP3430 fSound;
int32 fBuffer0;
int32 fBuffer1;
int32 fBuffer0Handle;
int32 fBuffer1Handle;
void *convert_buffer;
int fBufferLength;
int fBufferBytesPerRow;
int fBufferSequence;
bigtime_t fBufferPeriod;
bool started;
};
#endif
@@ -0,0 +1,177 @@
/*
Copyright (c) 2004, Thomas Kurschel
Part of Radeon In add-on
YUV converter
The Rage Theatre always provides YUV422 data and starting with Radeon, ATI
moved colour converter from 2D to 3D unit, so if you need another format you
must convert it manually, unless you get 3D working (which is, starting with r300,
hopeless anyway as there is no spec).
Colour temperature is according to BT.601; for YCbCr format see also GraphicsDefs.h
This header is included from VideoIn.cpp, with various defines to convert to
the wished format (RGB15, RGB16 or RGB32).
Things to improve:
- colour components should be interpolated for odd pixels
*/
static const int8 c_offs[8] =
{ 128, 128, 128, 128, 128, 128, 128, 128 };
static const int16 y_offs[4] =
{ 16*128, 16*128, 16*128, 16*128 };
static const uint16 masks[2][4] = {
// high byte mask
{ 0xff00, 0xff00, 0xff00, 0xff00 },
// low byte mask
{ 0x00ff, 0x00ff, 0x00ff, 0x00ff },
};
static const int16 scale[5][4] = {
// Y pre-scale
{ (int16)(1.1678 * 512), (int16)(1.1678 * 512), (int16)(1.1678 * 512), (int16)(1.1678 * 512) },
// CbG CrG CbG CrG
{ (int16)(-0.3929 * 256), (int16)(-0.8154 * 256), (int16)(-0.3929 * 256), (int16)(-0.8154 * 256) },
// CbB CrR CbB CrR
{ (int16)(2.0232 * 256), (int16)(1.6007 * 256), (int16)(2.0232 * 256), (int16)(1.6007 * 256) },
};
static const int8 masks_8bit[2][8] = {
// r/b 16 bit mask and r/g/b 15 bit mask
{ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 },
// g 16 bit mask
{ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc },
};
asm volatile(
"2:\n"
"pxor %%mm7,%%mm7\n"
"1:\n"
"movq (%0),%%mm0\n" // mm0 = Cr2'Y3' Cb2'Y2' Cr0'Y1' Cb0'Y0'
"movq %%mm0,%%mm1\n" // mm1 = Cr2'Y3' Cb2'Y2' Cr0'Y1' Cb0'Y0'
// Y is in 16..235
// we need to substract 16 and scale to full range
// as standard MMX has a _signed_ integer multiply only, the highest bit must
// be zero before scaling, i.e. we use signed format 9.7
"pand 8+%4,%%mm0\n" // mm2 = Y3' Y2' Y1' Y0'
"psllw $7,%%mm0\n"
"psubusw %3,%%mm0\n"
"pmulhw %5,%%mm0\n" // mm0 = Y3 Y2 Y1 Y0
// Cb and Cr is biased; compensate that
"psubb %2,%%mm1\n" // mm1 = Cr2 xxx Cb2 xxx Cr0 xxx Cb0 xxx
"pand %4,%%mm1\n" // mm1 = Cr2 Cb2 Cr0 Cb0
// transform Cb and Cr to green component
"movq %%mm1,%%mm2\n"
"pmaddwd 8+%5,%%mm1\n" // mm1 = CbCrG2 xxxxxxx CbCrG0 xxxxxxx
"psrad $16,%%mm1\n" // mm1 = CbCrG2 CbCrG0
"packssdw %%mm1,%%mm1\n" // mm1 = CbCrG2 CbCrG0 CbCrG2 CbCrG0
"punpcklwd %%mm1,%%mm1\n" // mm1 = CbCrG2 CbCrG2 CbCrG0 CbCrG0
// transform Cb to blue and Cr to red component
"pmulhw 16+%5,%%mm2\n" // mm2 = CrR2 CbB2 CrR0 CbB0
// nasty shuffling to separate and duplicate components
"movq %%mm2,%%mm3\n"
"punpcklwd %%mm3,%%mm3\n" // mm3 = CrR0 CrR0 CbB0 CbB0
"punpckhwd %%mm2,%%mm2\n" // mm2 = CrR2 CrR2 CbB2 CbB2
"movq %%mm3,%%mm4\n"
"punpckldq %%mm2,%%mm3\n" // mm3 = CbB2 CbB2 CbB0 CbB0
"punpckhdq %%mm2,%%mm4\n" // mm4 = CrR2 CrR2 CrR0 CrR0
// add Y to get final RGB
"paddsw %%mm0,%%mm1\n" // mm1 = G3 G2 G1 G0
"paddsw %%mm0,%%mm3\n" // mm3 = B3 B2 B1 B0
"paddsw %%mm0,%%mm4\n" // mm4 = R3 R2 R1 R0
// now, RBG can be converted to 8 bits each
"packuswb %%mm0,%%mm1\n" // mm1 = Y3 Y2 Y1 Y0 G3 G2 G1 G0
"packuswb %%mm4,%%mm3\n" // mm3 = R3 R2 R1 R0 B3 B2 B1 B0
#ifdef RGB32
// convertion to RGB32
"movq %%mm3,%%mm2\n"
"punpckhbw %%mm1,%%mm3\n" // mm3 = Y3 R3 Y2 R2 Y1 R1 Y0 R0
"punpcklbw %%mm1,%%mm2\n" // mm2 = G3 B3 G2 B2 G1 B1 G0 B0
"movq %%mm2,%%mm1\n"
"punpcklwd %%mm3,%%mm2\n"
"movq %%mm2,0x00(%1)\n" // dst = Y1 R1 G1 B1 Y0 R0 G0 B0
"punpckhwd %%mm3,%%mm1\n"
"movq %%mm1,0x08(%1)\n" // dst = Y3 R3 G3 B3 Y2 R2 G2 B2
"addl $0x08,%0\n" // source += 8
"addl $0x10,%1\n" // destination += 16
"subl $0x10,%7\n" // next pixels
#endif
#ifdef RGB16
// convertion to RGB16
// things would be much easier if Intel had added a RGB32->RGB16 instruction
"pand %6,%%mm3\n" // mm3 - R3 R2 R1 R0 B3 B2 B1 B0 (masked)
"pand 8+%6,%%mm1\n" // mm1 - Y3 Y2 Y1 Y0 G3 G2 G1 G0 (masked)
"punpcklbw %%mm7,%%mm1\n" // mm1 - G3 G2 G1 G0
"movq %%mm7,%%mm2\n"
"punpckhbw %%mm3,%%mm2\n" // mm2 - R3 R2 R1 R0
"punpcklbw %%mm7,%%mm3\n" // mm3 - B3 B2 B1 B0
"psllw $3,%%mm1\n" // mm1 - G3 G2 G1 G0
"psrlw $3,%%mm3\n" // mm3 - B3 B2 B1 B0
"por %%mm2,%%mm1\n"
"por %%mm3,%%mm1\n"
"movq %%mm1,(%1)\n"
"addl $0x08,%0\n" // source += 8
"addl $0x08,%1\n" // destination += 8
"subl $0x08,%7\n" // next pixels
#endif
#ifdef RGB15
// convertion to RGB15
// same problem as before
"pand %6,%%mm3\n" // mm3 - R3 R2 R1 R0 B3 B2 B1 B0 (masked)
"pand %6,%%mm1\n" // mm1 - Y3 Y2 Y1 Y0 G3 G2 G1 G0 (masked)
"punpcklbw %%mm7,%%mm1\n" // mm1 - G3 G2 G1 G0
"movq %%mm7,%%mm2\n"
"punpckhbw %%mm3,%%mm2\n" // mm2 - R3 R2 R1 R0
"punpcklbw %%mm7,%%mm3\n" // mm3 - B3 B2 B1 B0
"psllw $2,%%mm1\n" // mm1 - G3 G2 G1 G0
"psrlw $1,%%mm2\n" // mm2 - R3 R2 R1 R0
"psrlw $3,%%mm3\n" // mm3 - B3 B2 B1 B0
"por %%mm2,%%mm1\n"
"por %%mm3,%%mm1\n"
"movq %%mm1,(%1)\n"
"addl $0x08,%0\n" // source += 8
"addl $0x08,%1\n" // destination += 8
"subl $0x08,%7\n" // next pixels
#endif
// next
"jg 1b\n"
"movl %9,%7\n"
"subl %7,%8\n"
"jg 2b\n"
"emms\n"
:
: "r" (convert_buffer), "r" (bits), "m" (c_offs), "m" (y_offs),
"m" (masks), "m" (scale), "m" (masks_8bit),
"r" (bytesPerRow), "m" (bitsLength), "m" (bytesPerRow));