#define TRUE 1 #define FALSE 0 /* defines for calls to SetI2C, ON -> +5V, OFF -> 0 V */ #define CLKON 0 #define CLKOFF 0x8 #define DATON 0 #define DATOFF 0x4 static void SetI2C(unsigned char Clock, unsigned char Data) { /* set Clock and Data values */ unsigned char remain; remain = inportb(QQS_PORT + 2) & 0x3; /* keep tuner & tt selection */ outportb(QQS_PORT + 2, Clock | Data | remain); } static int GetI2C(void) { /* return whether data is ON */ return (inportb(QQS_PORT + 2) & 0x4) != 0; } static void StartI2C(void) { /* set I2C to start condition */ SetI2C(CLKON, DATOFF); SetI2C(CLKOFF, DATOFF); } static void StopI2C(void) { /* (re)set I2C to stop condition */ SetI2C(CLKON, DATOFF); SetI2C(CLKON, DATON); } static int SendByteI2C(unsigned char Byte) { /* send byte to I2C, I2C must be in startcondition (clk = 0), return whether success */ unsigned char bit; int result; for (bit = 0x80; bit; bit >>= 1) { /* send a bit */ SetI2C(CLKOFF, (Byte & bit) ? DATON : DATOFF); SetI2C(CLKON, (Byte & bit) ? DATON : DATOFF); udelay(110); SetI2C(CLKOFF, (Byte & bit) ? DATON : DATOFF); } /* get acknowledge */ SetI2C(CLKOFF, DATON); SetI2C(CLKON, DATON); udelay(110); result = !GetI2C(); /* must return FALSE, tuner has set DATOFF */ SetI2C(CLKOFF, DATOFF); return result; } static void RecByteI2C(unsigned char* Byte) { /* receive Byte from I2C, I2C must be in startcondition (clk = OFF) */ unsigned char bit; *Byte = 0; for (bit = 0x80; bit; bit >>= 1) { /* receive a bit */ SetI2C(CLKOFF, DATON); SetI2C(CLKON, DATON); udelay(110); if (GetI2C()) *Byte |= bit; } SetI2C(CLKOFF, DATON); } static int WriteI2C(int Count, unsigned char * Buffer) { /* write Buffer[0..Count-1] to I2C, return whether success */ StartI2C(); while (Count-- > 0) if (!SendByteI2C(*Buffer++)) break; /* not acknowledged */ StopI2C(); return Count < 0; } int InitTune(void) { /* return whether I2C functions correctly. if TRUE tuner is initialized. */ int result; SetI2C(CLKON, DATON); udelay(110); if (!GetI2C()) return FALSE; SetI2C(CLKON, DATOFF); udelay(110); result = !GetI2C(); StopI2C(); return result; } int GetStatus(unsigned char* Status) { /* get status from tuner, return whether success */ int result = TRUE; StartI2C(); if ((result = SendByteI2C(0xc3)) == TRUE) RecByteI2C(Status); StopI2C(); return result; } int SetFreq(unsigned long Freq) { /* set tuner to given frequency Freq in Hz, return whether success. InitTune() must have been called before use. */ unsigned char band, buffer[5]; unsigned int divider; if (Freq < 46000000L || Freq > 870000000L) return FALSE; if (Freq < 175250000L) band = 0xa0; /* low band */ else if (Freq < 455250000L) band = 0x90; /* mid band */ else band = 0x30; /* high band */ divider = (unsigned int)((Freq + 38900000L) / 62500L); buffer[0] = 0xc2; buffer[1] = (unsigned char)(divider >> 8); buffer[2] = (unsigned char)(divider & 0xff); buffer[3] = 0x8e; /* CP -> moderate tuning speed with quality */ buffer[4] = band; return WriteI2C(5, buffer); } int SelectChannel(unsigned long freq) { /* freq == 0 -> direct video, freq != 0 -> tune frequency freq on tuner. initializes tuner if neccesary, return whether success */ unsigned char tuneremain; int status; tuneremain = inportb(QQS_PORT + 2) & 1; /* keep tt interrupt on/off selection */ if (freq == 0) { outportb(QQS_PORT + 2, tuneremain); /* select video */ printk ("QQS tuner off\n"); return TRUE; } tuneremain |= 0x2; outportb(QQS_PORT + 2, tuneremain); /* select tuner */ status = SetFreq(freq); printk ("QQS tuner at %9d, status %2d\n", freq, status); return status; }