These files are a first cut of an X11 based "remote control" for
the Bt848 cards.  They require the FWF widget set.

-----
Files:

the makefile:			Imakefile
a startup script:		xtvr
top level resource file:	MyXremote	
resources for the channel face:	STB_CHNLS
resources for the picture face:	STB_PICTURE
another (out of date) resource:	Xtvremote.ad
the source:			xtvremote.cc
the binary:			xtvremote

-----
Usage:

xtvr is a simple script for testing.  It needs more work for a polished
X11 installation.

The resource file MyXremote can be modified to add other "faces".

The resource file STB_CHNLS provides buttons for changing channels.

The resource file STB_PICTURE provides buttons for setting picture
values such as hue and contrast.

The left pulldown is used to exit the program.

The center pulldown is used to select among "faces".

A fair amount of customization of the "faces" is possible via the
resources files, including the callbacks invoked.  A LOT more needs
to be written on this topic!

----------------------
various patches are necessary for the bt848 driver.  these will soon
make it into the driver, but for now:

---
in brooktree.c several things need attention.  1st, define the type of tuner
your board has.  The STB usually has a TEMIC, while the Wincast/TV uses
the PHILIPS.  It should be obvious from looking at the large tin can
on your board.

#define TEMIC_TUNER	/* for STB */

 OR

#define PHILIPS_TUNER	/* for Wincast/TV */

There are 2 bogus timing defines, if the tuner is erratic on a fast system
try doubling these:

#define SDELAY			2
#define LDELAY			20

---
you need to enable yourapplication to get its input from the
boards tuner:

	i = METEOR_INPUT_DEV1;
        if (ioctl(video, METEORSINPUT, &i) < 0) {
		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
		goto bybye;

	}

---
and finally the driver patches themselves:

-------------------------------------- cut -----------------------------------
*** ioctl_meteor.h	1997/02/27 05:41:32	1.1
--- ioctl_meteor.h	1997/02/28 04:28:53
***************
*** 71,76 ****
--- 71,91 ----
  	u_long	ramsize;	/* Size of Vram */
  };
  
+ #if defined( TUNER )
+ #define TUNERTYPE_NABCST	1
+ #define TUNERTYPE_CABLEIRC	2
+ #define TUNERTYPE_CABLEHRC	3
+ #define TUNERTYPE_WEUROPE	4
+ 
+ struct tvtuner {
+ 	int	opencount;
+ 	int	frequency;
+ 	u_char	tunertype;
+ 	u_char	channel;
+ 	u_char	band;
+ };
+ #endif /* TUNER */
+ 
  #define METEORCAPTUR _IOW('x', 1, int)			 /* capture a frame */
  #define METEORCAPFRM _IOW('x', 2, struct meteor_capframe)  /* sync capture */
  #define METEORSETGEO _IOW('x', 3, struct meteor_geomet)  /* set geometry */
***************
*** 106,111 ****
--- 121,134 ----
  #define METEORGVWS   _IOR('x', 19, unsigned char)	/* get vert start reg */
  #define	METEORSTS    _IOW('x', 20, unsigned char)	/* set time stamp */
  #define	METEORGTS    _IOR('x', 20, unsigned char)	/* get time stamp */
+ 
+ #if defined( TUNER )
+ #define	TVTUNER_SETCHNL    _IOW('x', 32, unsigned int)	/* set channel */
+ #define	TVTUNER_GETCHNL    _IOR('x', 32, unsigned int)	/* get channel */
+ #define	TVTUNER_SETTYPE    _IOW('x', 33, unsigned int)	/* set tuner type */
+ #define	TVTUNER_GETTYPE    _IOR('x', 33, unsigned int)	/* get tuner type */
+ #define	TVTUNER_GETSTATUS  _IOR('x', 34, unsigned int)	/* get tuner status */
+ #endif /* TUNER */
  
  #define	METEOR_STATUS_ID_MASK	0xf000	/* ID of 7196 */
  #define	METEOR_STATUS_DIR	0x0800	/* Direction of Expansion port YUV */
-------------------------------------- cut -----------------------------------


-------------------------------------- cut -----------------------------------
*** brktree_reg.h	1997/02/27 03:17:24	1.1
--- brktree_reg.h	1997/02/27 19:50:14
***************
*** 169,174 ****
--- 169,177 ----
      void	*devfs_token;
  #endif
      struct meteor_video video;
+ #if defined( TUNER )
+     struct tvtuner	tuner;
+ #endif /* TUNER */
  } bktr_reg_t;
-------------------------------------- cut -----------------------------------
  
  
-------------------------------------- cut -----------------------------------
*** brooktree848.c	1997/02/27 03:17:24	1.1
--- brooktree848.c	1997/03/08 07:58:57
***************
*** 140,150 ****
  #include <pci/pcivar.h>
  #include <pci/pcireg.h>
  #endif
  #include <machine/ioctl_meteor.h>
  #include <pci/brktree_reg.h>
  
! #define METPRI (PZERO+8)|PCATCH
  
  
  static void bktr_intr __P((void *arg));
  static bt_enable_cnt;
--- 140,156 ----
  #include <pci/pcivar.h>
  #include <pci/pcireg.h>
  #endif
+ 
+ #define TUNER
  #include <machine/ioctl_meteor.h>
  #include <pci/brktree_reg.h>
  
! #if defined( TUNER )
! static int	tv_channel __P(( bktr_reg_t* bktr, int channel ));
! static int	tuner_status __P(( bktr_reg_t* bktr ));
! #endif /* TUNER */
  
+ #define METPRI (PZERO+8)|PCATCH
  
  static void bktr_intr __P((void *arg));
  static bt_enable_cnt;
***************
*** 259,274 ****
      if (*btl_reg & (1 << 25) ) *btl_reg |= 1 << 8;
      bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT];
      t_pc = *bktr_pc;
!     /* printf(" STATUS %x %x %x \n", s_status, bktr_status, t_pc);  */
      if (!((bktr_status  & 0x800) || (bktr_status & 1 << 19 ))) {
        btl_status_prev = bktr_status;
        /*      return; */
      }
  
      /* if risc was disabled re-start process again */
      if (!(bktr_status & (1 << 27)) ||
  	( bktr_status & 0x8000)) {
! 
  
        btl_reg = (u_long *) &bt848[BKTR_INT_STAT];
        *btl_reg = *btl_reg;
--- 265,285 ----
      if (*btl_reg & (1 << 25) ) *btl_reg |= 1 << 8;
      bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT];
      t_pc = *bktr_pc;
! #if 0
!     printf(" STATUS %x %x %x \n", s_status, bktr_status, t_pc);
! #endif
      if (!((bktr_status  & 0x800) || (bktr_status & 1 << 19 ))) {
        btl_status_prev = bktr_status;
        /*      return; */
      }
  
      /* if risc was disabled re-start process again */
+ #if 0
      if (!(bktr_status & (1 << 27)) ||
  	( bktr_status & 0x8000)) {
! #else
!     if (!(bktr_status & (1 << 27)) || ((bktr_status & 0xfe000) != 0) ) {
! #endif
  
        btl_reg = (u_long *) &bt848[BKTR_INT_STAT];
        *btl_reg = *btl_reg;
***************
*** 1215,1222 ****
--- 1226,1243 ----
  	if (!(bktr->flags & METEOR_INITALIZED))	/* device not found */
  		return(ENXIO);	
  
+ #if defined( TUNER )
+ 	if (bktr->flags & METEOR_OPEN)		/* device already open */
+ 	{
+ 		bktr->tuner.opencount++;
+ 		return 0;
+ 	}
+ 	else
+ 		bktr->tuner.opencount = 1;	/* first open */
+ #else
  	if (bktr->flags & METEOR_OPEN)		/* device is busy */
  		return(EBUSY);
+ #endif /* tuner */
  
  	bktr->flags |= METEOR_OPEN;
  
***************
*** 1260,1265 ****
--- 1281,1290 ----
  	bktr->video.banksize = 0;
  	bktr->video.ramsize = 0;
  
+ #if defined( TUNER )
+ 	bktr->tuner.frequency = 0;
+ 	bktr->tuner.tunertype = TUNERTYPE_NABCST;
+ #endif /* TUNER */
  
  	return(0);
  }
***************
*** 1280,1285 ****
--- 1305,1316 ----
  		return(ENXIO);
  
  	bktr = &(brooktree[unit]);
+ 
+ #if defined( TUNER )
+ 	if ( --bktr->tuner.opencount > 0 )
+ 		return 0;
+ #endif /* tuner */
+ 
  	bktr->flags &= ~METEOR_OPEN;
  	bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
  	bktr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK);
***************
*** 1356,1361 ****
--- 1387,1393 ----
  	return(0);
  }
  
+ 
  int
  bktr_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
  {
***************
*** 1386,1391 ****
--- 1418,1445 ----
  
  	bt848 =  bktr->base;
  	switch (cmd) {
+ 
+ #if defined ( TUNER )
+ 	case TVTUNER_SETCHNL:
+ 		temp = tv_channel( bktr, (int)*(unsigned long *)arg );
+ 		if ( temp < 0 ) return EIO;
+ 		*(unsigned long *)arg = temp;
+ 		break;
+ 	case TVTUNER_GETCHNL:
+ 		*(unsigned long *)arg = bktr->tuner.channel;
+ 		break;
+ 	case TVTUNER_SETTYPE:
+ 		bktr->tuner.tunertype = *(unsigned long *)arg;
+ 		break;
+ 	case TVTUNER_GETTYPE:
+ 		*(unsigned long *)arg = bktr->tuner.tunertype;
+ 		break;
+ 	case TVTUNER_GETSTATUS:
+                 temp = tuner_status( bktr );
+ 		*(unsigned long *)arg = temp & 0xff;
+ 		break;
+ #endif /* TUNER */
+ 
  	case METEORSTATUS:	/* get 7196 status */
  		c_temp = bt848[0];
  		temp = 0;
***************
*** 1408,1413 ****
--- 1462,1468 ----
  			bt848[BKTR_O_CONTROL] &= ~0x40;
  
  			break;
+ #if 0
  		case METEOR_INPUT_DEV1:
  			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
  				| METEOR_DEV1;
***************
*** 1415,1421 ****
  			bt848[BKTR_IFORM] |= 0x40;
  			bt848[BKTR_E_CONTROL] |= 0x40;
  			bt848[BKTR_O_CONTROL] |= 0x40;
! 
  			break;
  
  		case METEOR_INPUT_DEV2:
--- 1470,1486 ----
  			bt848[BKTR_IFORM] |= 0x40;
  			bt848[BKTR_E_CONTROL] |= 0x40;
  			bt848[BKTR_O_CONTROL] |= 0x40;
! #else
! /* fixes lack of color */
! 		case METEOR_INPUT_DEV1:
! 			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
! 				| METEOR_DEV1;
! 			bt848[BKTR_IFORM] &= ~0x60;
! 			bt848[BKTR_IFORM] |= 0x40;
! 			
! 			bt848[BKTR_E_CONTROL] &= ~0x40;
! 			bt848[BKTR_O_CONTROL] &= ~0x40;
! #endif
  			break;
  
  		case METEOR_INPUT_DEV2:
***************
*** 1522,1527 ****
--- 1587,1593 ----
  	case METEORGBRIG:	/* get brightness */
  		*(u_char *)arg = bt848[BKTR_BRIGHT];
  		break;
+ #if 0
  	case METEORSCSAT:	/* set chroma saturation */
  	        s_temp =  *(u_short *)arg ;
  	        s_temp = s_temp << 1;
***************
*** 1539,1544 ****
--- 1605,1633 ----
  		*(u_short *)arg = (bt848[BKTR_E_CONTROL] << 8) &  0x10 | bt848[BKTR_SAT_U_LO];
  
  		break;
+ #else
+ 	case METEORSCSAT:	/* set chroma saturation */
+ 	        temp = (int)*(u_char *)arg ;
+ 
+ 		bt848[BKTR_SAT_U_LO] = bt848[BKTR_SAT_V_LO] =
+                   (temp << 1) & 0xff;
+ 
+ 		bt848[BKTR_E_CONTROL] &= ~0x3;		/* clear U/V MSBs */
+ 		bt848[BKTR_O_CONTROL] &= ~0x3;		/* clear U/V MSBs */
+ 
+ 		if ( temp & 0x80 ) {
+                     bt848[BKTR_E_CONTROL] |= 0x3;	/*  */
+                     bt848[BKTR_O_CONTROL] |= 0x3;
+                 }
+ 		break;
+ 
+ 	case METEORGCSAT:	/* get chroma saturation */
+                 temp = (bt848[BKTR_SAT_V_LO] >> 1) & 0xff;
+                 if ( bt848[BKTR_E_CONTROL] & 0x01 )
+                   temp |= 0x80;
+ 		*(u_char *)arg = (u_char)temp;
+ 		break;
+ #endif
  
  	case METEORSCONT:	/* set contrast */
  	        temp = *(u_char *)arg & 0xff;
***************
*** 1550,1558 ****
--- 1639,1657 ----
                  bt848[BKTR_O_CONTROL] |= ((temp & 0x100) >> 6 ) & 0x4 ;
  
  		break;
+ #if 0
  	case METEORGCONT:	/* get contrast */
  		*(u_short *)arg = bt848[BKTR_CONTRAST_LO] | ((bt848[BKTR_O_CONTROL] & 4) << 2);
  		break;
+ #else
+ 	case METEORGCONT:	/* get contrast */
+                 temp = (int)bt848[BKTR_CONTRAST_LO] & 0xff;
+ 		temp |= ((int)bt848[BKTR_O_CONTROL] & 0x04) << 6;
+ 		temp >>= 1;
+ 
+ 		*(u_char *)arg = (u_char)(temp & 0xff);
+ 		break;
+ #endif
  
  	case METEORSSIGNAL:
  
***************
*** 1846,1854 ****
  
  		break;
  		default:
  		  error = ENOTTY;
  		  break;
! 
  	}
  
  	return 0;
--- 1945,1956 ----
  
  		break;
  		default:
+ #if 0
  		  error = ENOTTY;
  		  break;
! #else
! 		  return ENODEV;
! #endif
  	}
  
  	return 0;
***************
*** 1882,1887 ****
--- 1984,2449 ----
  
  	return i386_btop(vtophys(bktr->bigbuf) + offset);
  }
+ 
+ 
+ #if defined( TUNER )
+ 
+ #define TEMIC_TUNER
+ 
+ /** FIXME: this should be a kernel option */
+ #define IF_FREQUENCY		4575	/* M/N IF frequency */
+ 
+ /* guaranteed address for any TSA5522 */
+ #define TSA5522_WADDR		0xc2
+ #define TSA5522_RADDR		0xc3
+ 
+ /*
+  * bit 7: CONTROL BYTE = 1
+  * bit 6: CP = 0		moderate speed tuning, better FM
+  * bit 5: T2 = 0		normal operation
+  * bit 4: T1 = 0		normal operation
+  * bit 3: T0 = 1		normal operation
+  * bit 2: RSA = 1		62.5kHz
+  * bit 1: RSB = 1		62.5kHz
+  * bit 0: OS = 0		normal operation
+  */
+ #define TSA5522_CONTROL		0x8e
+ 
+ #if defined( TEMIC_TUNER )
+ #define TSA5522_BANDA		0x02
+ #define TSA5522_BANDB		0x04
+ #define TSA5522_BANDC		0x01
+ #elif defined( PHILIPS_TUNER )
+ #define TSA5522_BANDA		0xa0
+ #define TSA5522_BANDB		0x90
+ #define TSA5522_BANDC		0x30
+ #else
+ #error you must define a tuner type
+ #endif
+ 
+ /* scaling factor for frequencies expressed as ints */
+ #define FREQFACTOR		100
+ 
+ 
+ /******************************* i2c primitives ******************************/
+ 
+ /* delays for the I2C bus transactions */
+ #define NDELAY			0
+ #define SDELAY			2
+ #define LDELAY			20
+ 
+ /* macros to show the details more clearly */
+ typedef volatile u_long*	i2c_regptr_t;
+ 
+ static inline void
+ DataLo_ClockLo( i2c_regptr_t bti2c, int delay )
+ {
+ 	*bti2c = 0;
+ 	if ( delay )
+ 		DELAY( delay );
+ }
+ static inline void
+ DataHi_ClockLo( i2c_regptr_t bti2c, int delay )
+ {
+ 	*bti2c = 1;
+ 	if ( delay )
+ 		DELAY( delay );
+ }
+ 
+ static inline void
+ DataLo_ClockHi( i2c_regptr_t bti2c, int delay )
+ {
+ 	*bti2c = 2;
+ 	if ( delay )
+ 		DELAY( delay );
+ }
+ 
+ static inline void
+ DataHi_ClockHi( i2c_regptr_t bti2c, int delay )
+ {
+ 	*bti2c = 3;
+ 	if ( delay )
+ 		DELAY( delay );
+ }
+ 
+ static inline int
+ DataRead( i2c_regptr_t bti2c )
+ {
+ 	return ( *bti2c & 1 );
+ }
+ 
+ 
+ /* forward reference */
+ static int i2cWrite( i2c_regptr_t, u_char );
+ 
+ /*
+  * start an I2C bus transaction
+  */
+ static void
+ i2cStart( i2c_regptr_t bti2c, int address )
+ {
+ 
+ #if 1
+ 	/* ensure the proper starting state */
+ 	DataHi_ClockLo( bti2c, LDELAY );	/* release data */
+ 	DataHi_ClockHi( bti2c, LDELAY );	/* release clock */
+ #endif
+ 	DataLo_ClockHi( bti2c, LDELAY );	/* lower data */
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* lower clock */
+ 
+ 	/* send the address of the device */
+         i2cWrite( bti2c, address );
+ }
+ 
+ /*
+  * stop an I2C bus transaction
+  */
+ static void
+ i2cStop( i2c_regptr_t bti2c )
+ {
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* lower clock & data */
+ 	DataLo_ClockHi( bti2c, LDELAY );	/* release clock */
+ 	DataHi_ClockHi( bti2c, LDELAY );	/* release data */
+ }
+ 
+ /*
+  * place a '1' bit on the I2C bus
+  */
+ static void
+ i2cHi( i2c_regptr_t bti2c )
+ {
+ 	DataHi_ClockLo( bti2c, LDELAY );	/* assert HI data */
+ 	DataHi_ClockHi( bti2c, LDELAY );	/* strobe clock */
+ 	DataHi_ClockLo( bti2c, LDELAY );	/* release clock */
+ }
+ 
+ /*
+  * place a '0' bit on the I2C bus
+  */
+ static void
+ i2cLo( i2c_regptr_t bti2c )
+ {
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* assert LO data */
+ 	DataLo_ClockHi( bti2c, LDELAY );	/* strobe clock */
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* release clock */
+ }
+ 
+ /*
+  * give an 'ACK' to the slave
+  */
+ static void
+ i2cGrantAck( i2c_regptr_t bti2c )
+ {
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* assert LO data */
+ 	DataLo_ClockHi( bti2c, LDELAY );	/* strobe clock */
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* remove clock */
+ 	DataHi_ClockLo( bti2c, NDELAY );	/* float data */
+ }
+ 
+ /*
+  * get an 'ACK' from the slave
+  */
+ static int
+ i2cAck( i2c_regptr_t bti2c )
+ {
+ 	int acknowledge;
+ 
+ 	DataHi_ClockLo( bti2c, LDELAY );	/* float data */
+ 	DataHi_ClockHi( bti2c, LDELAY );	/* strobe clock */
+ 
+         acknowledge = DataRead( bti2c );	/* read ACK bit */
+ 
+ 	DataHi_ClockLo( bti2c, LDELAY );	/* release clock */
+ 
+ 	return acknowledge;
+ }
+ 
+ /*
+  * read a byte from the I2C bus
+  */
+ static int
+ i2cRead( i2c_regptr_t bti2c )
+ {
+ 	int x;
+         int byte;
+ 
+ 	DataHi_ClockLo( bti2c, SDELAY );	/* float data */
+ 
+         for ( byte = 0, x = 7; x >= 0; --x )
+         {
+ 		DataHi_ClockHi( bti2c, SDELAY );	/* strobe clock */
+ 
+ 		if ( DataRead( bti2c ) )		/* read data */
+ 			byte |= (1<<x);			/* bit was Hi */
+ 
+ 		DataHi_ClockLo( bti2c, SDELAY );	/* release clock */
+         }
+ #if 0
+         i2cHi( bti2c );				/* ??? */
+ #else
+ 	i2cGrantAck( bti2c );			/* Grant ACK */
+ #endif
+         return byte;
+ }
+ 
+ /*
+  * write a byte to the I2C bus
+  */
+ static int
+ i2cWrite( i2c_regptr_t bti2c, u_char byte )
+ {
+ 	int x;
+ 
+ 	DataLo_ClockLo( bti2c, LDELAY );	/* lower data & clock */
+ 
+         for ( x = 7; x >= 0; --x )
+ 		(byte & (1<<x)) ? i2cHi( bti2c ) : i2cLo( bti2c );
+ 
+         return i2cAck( bti2c );
+ }
+ 
+ #undef NDELAY
+ #undef SDELAY
+ #undef LDELAY
+ 
+ /*************************** end of i2c primitives ***************************/
+ 
+ 
+ #define I2C_REGADDR()		(i2c_regptr_t)&bktr->base[ BKTR_I2C_CONTROL ]
+ 
+ /*
+  * set the frequency of the tuner
+  */
+ static int
+ tv_freq( bktr_reg_t* bktr, int frequency )
+ {
+ 	i2c_regptr_t	bti2c;
+ 	u_char		band;
+ 	int		N;
+         int		order;
+ 
+         /* select the band based on frequency */
+ 	if ( frequency < (160 * FREQFACTOR) )
+ 		band = TSA5522_BANDA;
+         else if ( frequency < (454 * FREQFACTOR) )
+ 		band = TSA5522_BANDB;
+         else
+ 		band = TSA5522_BANDC;
+ 
+ 	/*
+ 	 * N = 16 * { fRF(pc) + fIF(pc) }
+ 	 * where:
+          *  pc is picture carrier, fRF & fIF are in mHz
+ 	 *
+ 	 * frequency is mHz to 2 decimal places, ie. 5525 == 55.25 mHz,
+ 	 *  dont want to do float in a driver!
+ 	 */
+ 	N = 16 * ((frequency + IF_FREQUENCY) / FREQFACTOR);
+ 
+ 	/* get the i2c register address */
+         bti2c = I2C_REGADDR();
+ 
+         /* send the data to the TSA5522 */
+         disable_intr();
+         i2cStart( bti2c, TSA5522_WADDR );
+ 
+         /* the data sheet wants the order set according to direction */
+         if ( frequency > bktr->tuner.frequency )
+         {
+ 	        i2cWrite( bti2c, (N >> 8) & 0x7f );	/* divisor MSB */
+         	i2cWrite( bti2c, N & 0xff );		/* divisor LSB */
+ 	        i2cWrite( bti2c, TSA5522_CONTROL );	/* control bits */
+         	i2cWrite( bti2c, band );		/* band select */
+         }
+         else
+         {
+ 	        i2cWrite( bti2c, TSA5522_CONTROL );	/* control bits */
+         	i2cWrite( bti2c, band );		/* band select */
+ 	        i2cWrite( bti2c, (N >> 8) & 0x7f );	/* divisor MSB */
+         	i2cWrite( bti2c, N & 0xff );		/* divisor LSB */
+         }
+ 
+         i2cStop( bti2c );
+         enable_intr();
+ 
+         return 0;
+ }
+ 
+ 
+ /*
+  * North American Broadcast Channels:
+  *
+  * IF freq: 45.75 mHz
+  *
+  * Chnl Freq
+  *  2	 55.25 mHz
+  *  3	 61.25 mHz
+  *  4	 67.25 mHz
+  * 
+  *  5	 77.25 mHz
+  *  6	 83.25 mHz
+  * 
+  *  7	175.25 mHz
+  * 13	211.25 mHz
+  * 
+  * 14	471.25 mHz
+  * 83	885.25 mHz
+  */
+ static int
+ frequency_nabcst( int channel )
+ {
+ 	/* legal channels are 2 thru 83 */
+         if ( channel > 83 )
+ 		return -1;
+ 
+ 	/* channels 14 thru 83 */
+         if ( channel >= 14 )
+ 		return 47125 + ((channel-14) * 600 );
+ 
+ 	/* channels 7 thru 13 */
+         if ( channel >= 7 )
+ 		return 17525 + ((channel-7) * 600 );
+ 
+ 	/* channels 5 thru 6 */
+         if ( channel >= 5 )
+ 		return 7725 + ((channel-5) * 600 );
+ 
+ 	/* channels 2 thru 4 */
+         if ( channel >= 2 )
+ 		return 5525 + ((channel-2) * 600 );
+ 
+ 	/* legal channels are 2 thru 83 */
+ 	return -1;
+ }
+ 
+ 
+ /*
+  * North American Cable Channels, IRC(?):
+  *
+  * IF freq: 45.75 mHz
+  *
+  * Chnl Freq
+  *  2	 55.25 mHz
+  *  3	 61.25 mHz
+  *  4	 67.25 mHz
+  *
+  *  5	 77.25 mHz
+  *  6	 83.25 mHz
+  *
+  *  7	175.25 mHz
+  * 13	211.25 mHz
+  *
+  * 14	121.25 mHz
+  * 22	169.25 mHz
+  *
+  * 23	217.25 mHz
+  * 94	643.25 mHz
+  *
+  * 95	 91.25 mHz
+  * 99	115.25 mHz
+  */
+ static int
+ frequency_irccable( int channel )
+ {
+ 	/* legal channels are 2 thru 99 */
+         if ( channel > 99 )
+ 		return -1;
+ 
+ 	/* channels 95 thru 99 */
+         if ( channel >= 95 )
+ 		return 9125 + ((channel-95) * 600 );
+ 
+ 	/* channels 23 thru 94 */
+         if ( channel >= 23 )
+ 		return 21725 + ((channel-23) * 600 );
+ 
+ 	/* channels 14 thru 22 */
+         if ( channel >= 14 )
+ 		return 12125 + ((channel-14) * 600 );
+ 
+ 	/* channels 7 thru 13 */
+         if ( channel >= 7 )
+ 		return 17525 + ((channel-7) * 600 );
+ 
+ 	/* channels 5 thru 6 */
+         if ( channel >= 5 )
+ 		return 7725 + ((channel-5) * 600 );
+ 
+ 	/* channels 2 thru 4 */
+         if ( channel >= 2 )
+ 		return 5525 + ((channel-2) * 600 );
+ 
+ 	/* legal channels are 2 thru 99 */
+ 	return -1;
+ }
+ 
+ 
+ /*
+  * set the channel of the tuner
+  */
+ static int
+ tv_channel( bktr_reg_t* bktr, int channel )
+ {
+ 	int frequency, status;
+ 
+ 	/* calculate the frequency according to tuner type */
+         switch ( bktr->tuner.tunertype )
+         {
+         case TUNERTYPE_NABCST:
+ 		frequency = frequency_nabcst( channel );
+ 		break;
+ 
+         case TUNERTYPE_CABLEIRC:
+ 		frequency = frequency_irccable( channel );
+ 		break;
+ 
+ 	/* FIXME: */
+         case TUNERTYPE_CABLEHRC:
+         case TUNERTYPE_WEUROPE:
+ 	default:
+                 return -1;
+         }
+ 
+ 	/* check the result of channel to frequency conversion */
+         if ( frequency < 0 )
+ 		return -1;
+ 
+         /* set the new frequency */
+ 	if ( tv_freq( bktr, frequency ) < 0 )
+ 		return -1;
+ 
+ 	/* OK to update records */
+ 	bktr->tuner.frequency = frequency;
+ 	bktr->tuner.channel = channel;
+ 
+ 	return channel;
+ }
+ 
+ /*
+  * set the channel of the tuner
+  */
+ static int
+ tuner_status( bktr_reg_t* bktr )
+ {
+ 	i2c_regptr_t	bti2c;
+ 	int		status;
+ 
+ 	/* get the i2c register address */
+         bti2c = I2C_REGADDR();
+ 
+         /* send the request to the TSA5522 */
+         disable_intr();
+         i2cStart( bti2c, TSA5522_RADDR );
+ 
+         status = i2cRead( bti2c );
+ 
+         i2cStop( bti2c );
+         enable_intr();
+ 
+         return status;
+ }
+ 
+ #endif /* TUNER */
  
  
  #if !defined(METEOR_FreeBSD_210)	/* XXX */
-------------------------------------- cut -----------------------------------
