#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "xf86i2c.h"
#include "bt829.h"
#include "i2c_def.h"
#define HCROP 0
#define VCROP 0
#define BTVERSION (bt->id>>4)
#define H(X) ( ((X)>>8) & 0xFF )
#define L(X) ( (X) & 0xFF )
#define LIMIT(X,A,B) (((X)<(A)) ? (A) : ((X)>(B)) ? (B) : (X) )
#define BT815 0x02
#define BT817 0x06
#define BT819 0x07
#define BT827 0x0C
#define BT829 0x0E
#define STATUS 0x00
#define IFORM 0x01
#define TDEC 0x02
#define CROP 0x03
#define VDELAY_LO 0x04
#define VACTIVE_LO 0x05
#define HDELAY_LO 0x06
#define HACTIVE_LO 0x07
#define HSCALE_HI 0x08
#define HSCALE_LO 0x09
#define BRIGHT 0x0A
#define CONTROL 0x0B
#define CONTRAST_LO 0x0C
#define SAT_U_LO 0x0D
#define SAT_V_LO 0x0E
#define HUE 0x0F
#define SCLOOP 0x10
#define WC_UP 0x11
#define OFORM 0x12
#define VSCALE_HI 0x13
#define VSCALE_LO 0x14
#define TEST 0x15
#define VPOLE 0x16
#define IDCODE 0x17
#define ADELAY 0x18
#define BDELAY 0x19
#define ADC 0x1A
#define VTC 0x1B
#define CC_STATUS 0x1C
#define CC_DATA 0x1D
#define WC_DN 0x1E
#define SRESET 0x1F
#define P_IO 0x3F
static CARD8 btread(BT829Ptr bt, CARD8 reg)
{
CARD8 v;
I2C_WriteRead(&(bt->d), ®, 1, &v, 1);
return v;
}
static void btwrite(BT829Ptr bt, CARD8 reg, CARD8 val)
{
CARD8 data[2];
data[0] = reg;
data[1] = val;
I2C_WriteRead(&(bt->d), data, 2, NULL, 0);
}
static void btwrite_status(BT829Ptr bt)
{
btwrite(bt, STATUS, 0x00);
}
static void btwrite_iform(BT829Ptr bt)
{
int xtsel;
switch (bt->format) {
case BT829_NTSC:
case BT829_NTSC_JAPAN:
case BT829_PAL_M:
case BT829_PAL_N_COMB:
xtsel = 1;
break;
case BT829_PAL:
case BT829_PAL_N:
case BT829_SECAM:
xtsel = 2;
break;
default:
xtsel = 3;
break;
}
btwrite(bt, IFORM, (bt->mux<<5) | (xtsel<<3) | bt->format);
}
static void btwrite_tdec(BT829Ptr bt)
{
}
static void btwrite_crop(BT829Ptr bt)
{
btwrite(bt, CROP, (H(bt->vdelay)<<6) | (H(bt->vactive)<<4) |
(H(bt->hdelay)<<2) | H(bt->width));
}
static void btwrite_vdelay_lo(BT829Ptr bt)
{
btwrite(bt, VDELAY_LO, L(bt->vdelay));
}
static void btwrite_vactive_lo(BT829Ptr bt)
{
btwrite(bt, VACTIVE_LO, L(bt->vactive));
}
static void btwrite_hdelay_lo(BT829Ptr bt)
{
btwrite(bt, HDELAY_LO, L(bt->hdelay));
}
static void btwrite_hactive_lo(BT829Ptr bt)
{
btwrite(bt, HACTIVE_LO, L(bt->width));
}
static void btwrite_hscale_hi(BT829Ptr bt)
{
btwrite(bt, HSCALE_HI, H(bt->hscale));
}
static void btwrite_hscale_lo(BT829Ptr bt)
{
btwrite(bt, HSCALE_LO, L(bt->hscale));
}
static void btwrite_bright(BT829Ptr bt)
{
btwrite(bt, BRIGHT, bt->brightness);
}
static void btwrite_control(BT829Ptr bt)
{
int ldec;
ldec = (bt->width > 360);
btwrite(bt, CONTROL,
((bt->mux==bt->svideo_mux) ? 0xC0:0x00) |
(ldec<<5) | (H(bt->contrast)<<2) | (H(bt->sat_u)<<1) | H(bt->sat_v));
}
static void btwrite_contrast_lo(BT829Ptr bt)
{
btwrite(bt, CONTRAST_LO, L(bt->contrast));
}
static void btwrite_sat_u_lo(BT829Ptr bt)
{
btwrite(bt, SAT_U_LO, L(bt->sat_u));
}
static void btwrite_sat_v_lo(BT829Ptr bt)
{
btwrite(bt, SAT_V_LO, L(bt->sat_v));
}
static void btwrite_hue(BT829Ptr bt)
{
btwrite(bt, HUE, bt->hue);
}
static void btwrite_scloop(BT829Ptr bt)
{
if (BTVERSION >= BT827) {
btwrite(bt, SCLOOP,
(bt->format==BT829_SECAM) ? 0x10:0x00
);
}
}
static void btwrite_wc_up(BT829Ptr bt)
{
if (BTVERSION >= BT827) {
}
}
static void btwrite_oform(BT829Ptr bt)
{
btwrite(bt, OFORM, (bt->code<<3) | (bt->len<<2) |
0x02
);
}
static void btwrite_vscale_hi(BT829Ptr bt)
{
btwrite(bt, VSCALE_HI, H(bt->vscale) |
0x60
);
}
static void btwrite_vscale_lo(BT829Ptr bt)
{
btwrite(bt, VSCALE_LO, L(bt->vscale));
}
static void btwrite_vpole(BT829Ptr bt)
{
btwrite(bt, VPOLE, (bt->out_en<<7));
}
static void btwrite_adelay(BT829Ptr bt)
{
switch (bt->format) {
case BT829_NTSC:
case BT829_NTSC_JAPAN:
case BT829_PAL_M:
btwrite(bt, ADELAY, 104);
break;
case BT829_PAL:
case BT829_PAL_N:
case BT829_SECAM:
case BT829_PAL_N_COMB:
btwrite(bt, ADELAY, 127);
break;
default:
btwrite(bt, ADELAY, 104);
break;
}
}
static void btwrite_bdelay(BT829Ptr bt)
{
switch (bt->format) {
case BT829_NTSC:
case BT829_NTSC_JAPAN:
case BT829_PAL_M:
btwrite(bt, BDELAY, 93);
break;
case BT829_PAL:
case BT829_PAL_N:
case BT829_PAL_N_COMB:
btwrite(bt, BDELAY, 114);
break;
case BT829_SECAM:
btwrite(bt, BDELAY, 160);
break;
default:
btwrite(bt, BDELAY, 93);
break;
}
}
static void btwrite_adc(BT829Ptr bt)
{
btwrite(bt, ADC, bt->mux==bt->svideo_mux ? 0x80:0x82);
}
static void btwrite_vtc(BT829Ptr bt)
{
int vfilt = 0;
if (BTVERSION > BT827) {
switch (bt->format) {
case BT829_NTSC:
case BT829_NTSC_JAPAN:
case BT829_PAL_M:
case BT829_PAL_N_COMB:
if (bt->width <= 360) vfilt = 1;
if (bt->width <= 180) vfilt = 2;
if (bt->width <= 90) vfilt = 3;
break;
case BT829_PAL:
case BT829_PAL_N:
case BT829_SECAM:
if (bt->width <= 384) vfilt = 1;
if (bt->width <= 192) vfilt = 2;
if (bt->width<= 96) vfilt = 3;
break;
default:
break;
}
btwrite(bt, VTC, (bt->vbien<<4) | (bt->vbifmt<<3) | vfilt);
}
}
static void btwrite_cc_status(BT829Ptr bt)
{
if (BTVERSION >= BT827) {
if (bt->ccmode == 0) btwrite(bt, CC_STATUS, 0x00);
else btwrite(bt, CC_STATUS, (bt->ccmode<<4) | 0x40);
}
}
static void btwrite_wc_dn(BT829Ptr bt)
{
if (BTVERSION >= BT827) {
}
}
static void bt_reset(BT829Ptr bt) {
btwrite(bt, SRESET, 0x0);
}
static void btwrite_p_io(BT829Ptr bt)
{
if (BTVERSION >= BT827) {
btwrite(bt, P_IO, bt->p_io);
}
}
static void propagate_changes(BT829Ptr bt)
{
CARD16 hdelay, unscaled_hdelay, vdelay, hscale, vscale;
int htotal, vactive;
switch (bt->format) {
case BT829_NTSC:
case BT829_NTSC_JAPAN:
case BT829_PAL_M:
vdelay = 22;
htotal = 754;
vactive = 480;
unscaled_hdelay = 135;
break;
case BT829_PAL:
case BT829_PAL_N:
vdelay = (bt->tunertype==5) ? 34 : 22;
htotal = 922;
vactive = 576;
unscaled_hdelay = 186;
break;
case BT829_SECAM:
vdelay = 34;
htotal = 922;
vactive = 576;
unscaled_hdelay = 186;
break;
case BT829_PAL_N_COMB:
vdelay = (bt->tunertype==5) ? 34 : 22;
htotal = 754;
vactive = 576;
unscaled_hdelay = 135;
break;
default:
vdelay = 22;
htotal = 754;
vactive = 480;
unscaled_hdelay = 135;
break;
}
bt->htotal = htotal;
hscale = 4096 * htotal / (bt->width + 2 * HCROP)-4096;
hdelay = (
HCROP + (bt->width + 2 * HCROP) * unscaled_hdelay / htotal
) & 0x3FE;
vactive = vactive - 2 * VCROP;
vdelay = vdelay + VCROP;
vscale = (0x10000 - (512*vactive/bt->height-512)) & 0x1FFF;
if ((hdelay != bt->hdelay) || (vdelay != bt->vdelay) ||
(vactive != bt->vactive) || (hscale != bt->hscale) ||
(vscale != bt->vscale)) {
bt->hdelay = hdelay;
bt->vdelay = vdelay;
bt->vactive = vactive;
bt->hscale = hscale;
bt->vscale = vscale;
btwrite_crop(bt);
btwrite_vdelay_lo(bt);
btwrite_vactive_lo(bt);
btwrite_hdelay_lo(bt);
btwrite_hscale_hi(bt);
btwrite_hscale_lo(bt);
btwrite_control(bt);
btwrite_vscale_hi(bt);
btwrite_vscale_lo(bt);
}
}
static void write_all(BT829Ptr bt)
{
bt_reset(bt);
propagate_changes(bt);
btwrite_iform(bt);
btwrite_tdec(bt);
btwrite_crop(bt);
btwrite_vdelay_lo(bt);
btwrite_vactive_lo(bt);
btwrite_hdelay_lo(bt);
btwrite_hactive_lo(bt);
btwrite_hscale_hi(bt);
btwrite_hscale_lo(bt);
btwrite_bright(bt);
btwrite_control(bt);
btwrite_contrast_lo(bt);
btwrite_sat_u_lo(bt);
btwrite_sat_v_lo(bt);
btwrite_hue(bt);
btwrite_scloop(bt);
btwrite_wc_up(bt);
btwrite_oform(bt);
btwrite_vscale_hi(bt);
btwrite_vscale_lo(bt);
btwrite_vpole(bt);
btwrite_adelay(bt);
btwrite_bdelay(bt);
btwrite_adc(bt);
btwrite_vtc(bt);
btwrite_wc_dn(bt);
btwrite_p_io(bt);
}
BT829Ptr bt829_Detect(I2CBusPtr b, I2CSlaveAddr addr)
{
BT829Ptr bt;
I2CByte a;
bt = xcalloc(1, sizeof(BT829Rec));
if(bt == NULL) return NULL;
bt->d.DevName = strdup("BT829 video decoder");
bt->d.SlaveAddr = addr;
bt->d.pI2CBus = b;
bt->d.NextDev = NULL;
bt->d.StartTimeout = b->StartTimeout;
bt->d.BitTimeout = b->BitTimeout;
bt->d.AcknTimeout = b->AcknTimeout;
bt->d.ByteTimeout = b->ByteTimeout;
if(!I2C_WriteRead(&(bt->d), NULL, 0, &a, 1))
{
free(bt);
return NULL;
}
bt->id = btread(bt,IDCODE);
free(bt->d.DevName);
bt->d.DevName = xcalloc(200, sizeof(char));
switch(BTVERSION){
case BT815:
sprintf(bt->d.DevName, "bt815a video decoder, revision %d",bt->id & 0xf);
break;
case BT817:
sprintf(bt->d.DevName, "bt817a video decoder, revision %d",bt->id & 0xf);
break;
case BT819:
sprintf(bt->d.DevName, "bt819a video decoder, revision %d",bt->id & 0xf);
break;
case BT827:
sprintf(bt->d.DevName, "bt827a/b video decoder, revision %d",bt->id & 0xf);
break;
case BT829:
sprintf(bt->d.DevName, "bt829a/b video decoder, revision %d",bt->id & 0xf);
break;
default:
sprintf(bt->d.DevName, "bt8xx/unknown video decoder version %d, revision %d",bt->id >> 4,bt->id & 0xf);
break;
}
if(!I2CDevInit(&(bt->d)))
{
free(bt);
return NULL;
}
bt->tunertype = 1;
bt->brightness = 0;
bt->ccmode = 0;
bt->code = 0;
bt->contrast = 216;
bt->format = BT829_NTSC;
bt->height = 480;
bt->hue = 0;
bt->len = 1;
bt->mux = BT829_MUX0;
bt->out_en = 0;
bt->p_io = 0;
bt->sat_u = 254;
bt->sat_v = 180;
bt->vbien = 0;
bt->vbifmt = 0;
bt->width = 640;
bt->hdelay = 120;
bt->hscale = 684;
bt->vactive = 480;
bt->vdelay = 22;
bt->vscale = 0;
bt->htotal = 754;
bt->svideo_mux = 0;
return bt;
}
int bt829_ATIInit(BT829Ptr bt)
{
bt->code = 1;
bt->len = 0;
bt->vbien = 1;
bt->vbifmt = 1;
bt->svideo_mux = BT829_MUX1;
write_all (bt);
return 0;
}
int bt829_SetFormat(BT829Ptr bt, CARD8 format)
{
if ((format < 1) || (format > 7)) return -1;
if ((BTVERSION <= BT819) &&
(format != BT829_NTSC) && (format != BT829_PAL)) return -1;
if (format == bt->format) return 0;
bt->format = format;
propagate_changes(bt);
btwrite_iform(bt);
btwrite_scloop(bt);
btwrite_adelay(bt);
btwrite_bdelay(bt);
btwrite_vtc(bt);
return 0;
}
int bt829_SetMux(BT829Ptr bt, CARD8 mux)
{
if ((mux < 1) || (mux > 3)) return -1;
if (mux == bt->mux) return 0;
bt->mux = mux;
btwrite_iform(bt);
btwrite_control(bt);
btwrite_adc(bt);
return 0;
}
void bt829_SetBrightness(BT829Ptr bt, int brightness)
{
brightness = LIMIT(brightness,-1000,999);
brightness = (128*brightness)/1000;
if (brightness == bt->brightness) return;
bt->brightness = brightness;
btwrite_bright(bt);
}
void bt829_SetContrast(BT829Ptr bt, int contrast)
{
contrast = LIMIT(contrast,-1000,1000);
contrast = (216*(contrast+1000))/1000;
if (contrast == bt->contrast) return;
bt->contrast = contrast;
btwrite_control(bt);
btwrite_contrast_lo(bt);
}
void bt829_SetSaturation(BT829Ptr bt, int saturation)
{
CARD16 sat_u, sat_v;
saturation = LIMIT(saturation,-1000,1000);
sat_u = (254*(saturation+1000))/1000;
sat_v = (180*(saturation+1000))/1000;
if ((sat_u == bt->sat_u) && (sat_v == bt->sat_v)) return;
bt->sat_u = sat_u;
bt->sat_v = sat_v;
btwrite_control(bt);
btwrite_sat_u_lo(bt);
btwrite_sat_v_lo(bt);
}
void bt829_SetTint(BT829Ptr bt, int hue)
{
hue = LIMIT(hue,-1000,999);
hue = (128*hue)/1000;
if (hue == bt->hue) return;
bt->hue = hue;
btwrite_hue(bt);
}
int bt829_SetCaptSize(BT829Ptr bt, int width, int height)
{
if ((width > bt->htotal - 2 * HCROP) ||
(16 * width < bt->htotal - 32 * HCROP)) return -1;
if ((height > bt->vactive) || (16 * height < bt->vactive)) return -1;
if ((width == bt->width) && (height == bt->height)) return 0;
bt->width = width;
bt->height = height;
propagate_changes(bt);
btwrite_crop(bt);
btwrite_hactive_lo(bt);
btwrite_control(bt);
btwrite_vtc(bt);
return 0;
}
int bt829_SetCC(BT829Ptr bt)
{
if (BTVERSION < BT827) return -1;
btwrite_cc_status(bt);
if (bt->ccmode != 0) btwrite_status(bt);
return 0;
}
void bt829_SetOUT_EN(BT829Ptr bt, BOOL out_en)
{
out_en = (out_en != 0);
if (out_en == bt->out_en) return;
bt->out_en = out_en;
btwrite_vpole(bt);
}
void bt829_SetP_IO(BT829Ptr bt, CARD8 p_io)
{
if (p_io == bt->p_io) return;
bt->p_io = p_io;
btwrite_p_io(bt);
}
#define BTREAD(R) btread(bt,(R))
#if 0
void bt829_getCCdata(BT829Ptr bt,struct CCdata *data)
{
CARD8 status;
data->num_valid=0;
if(!(BTREAD(STATUS)&0x04)) return;
for(;data->num_valid<CC_FIFO_SIZE;data->num_valid++) {
status=BTREAD(CC_STATUS);
if(!(status&0x04)) break;
data->data[data->num_valid]= BTREAD(CC_DATA)&0x7f;
data->status[data->num_valid]= (CCS_EDS*((status&0x02)>>1)) |
(CCS_HIGH*(status&0x01)) |
(CCS_OVER*((status&0x08)>>3)) |
(CCS_PAR*((status&0x80)>>7)) ; }
btwrite(bt,STATUS,0x00);
return;
}
#endif
#define DUMPREG(REG) \
xf86DrvMsg(bt->d.pI2CBus->scrnIndex,X_INFO," %-12s (0x%02X) = 0x%02X\n", \
#REG,REG,BTREAD(REG))