Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Feb 1997 19:41:52 -0700
From:      Steve Passe <smp@csn.net>
To:        multimedia@freebsd.org
Cc:        Randall Hopper <rhh@ct.picker.com>
Subject:   Re: STB tuner 
Message-ID:  <199702280241.TAA00216@clem.systemsix.com>
In-Reply-To: Your message of "Thu, 27 Feb 1997 12:03:28 MST." <199702271903.MAA28139@clem.systemsix.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
Hi,


several people have requested my code for the tuner.  its still very
rough, but more or less works.  note in particular I was just making
changes to allow multiple opens so that I could open the device
with both 'tv' and a 'remote' program to tickle the tuner while its
running.  this works, but doesn't shut down properly.  be sure to
start tv first, and close it last! (still might not close properly...)

The files patched:

src/sys/i386/include/ioctl_meteor.h
src/sys/pci/brktree_reg.h
src/sys/pci/brooktree848.c

tv.c  <- Note: this is the modified version that runs in a movable X window
	that was posted several days ago.

chnl.c  a very simple test program for the tuner.  start it after tv,
	then enter channel #s.  no prompt, no feedback, but hopefully the 
	channel will change.

-------------------------------------- cut ------------------------------------*** ioctl_meteor.h	1997/02/27 05:41:32	1.1
--- ioctl_meteor.h	1997/02/27 22:51:43
***************
*** 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,133 ----
  #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 */
+ #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/02/27 22:58:02
***************
*** 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,155 ----
  #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 ));
! #endif /* TUNER */
  
+ #define METPRI (PZERO+8)|PCATCH
  
  static void bktr_intr __P((void *arg));
  static bt_enable_cnt;
***************
*** 1215,1222 ****
--- 1220,1237 ----
  	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 ****
--- 1275,1284 ----
  	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 ****
--- 1299,1310 ----
  		return(ENXIO);
  
  	bktr = &(brooktree[unit]);
+ 
+ #if defined( TUNER )
+ 	if ( --(bktr->tuner.opencount) )
+ 		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 ****
--- 1381,1387 ----
  	return(0);
  }
  
+ 
  int
  bktr_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
  {
***************
*** 1386,1391 ****
--- 1412,1435 ----
  
  	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;
+ #endif /* TUNER */
+ 
  	case METEORSTATUS:	/* get 7196 status */
  		c_temp = bt848[0];
  		temp = 0;
***************
*** 1882,1887 ****
--- 1926,2238 ----
  
  	return i386_btop(vtophys(bktr->bigbuf) + offset);
  }
+ 
+ 
+ #if defined( TUNER )
+ 
+ /** FIXME: this should be a kernel option */
+ #define IF_FREQUENCY		4575	/* M/N IF frequency */
+ 
+ /* guaranteed address for any TSA5522 */
+ #define TSA5522_ADDR		0xc2
+ 
+ /*
+  * 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
+ 
+ #define TSA5522_BANDA		0x02
+ #define TSA5522_BANDB		0x04
+ #define TSA5522_BANDC		0x01
+ 
+ /* scaling factor for frequencies expressed as ints */
+ #define FREQFACTOR		100
+ 
+ /* delays for the I2C bus transactions */
+ #define I2C_SDELAY		2
+ #define I2C_LDELAY		20
+ 
+ /*
+  * start an I2C bus transaction
+  */
+ static void
+ i2cStart( volatile u_long* bti2c )
+ {
+ #if 1
+ 	*bti2c = 1;			/* raise data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 3;			/* data hi, raise clock */
+ 	DELAY( I2C_LDELAY );
+ #endif
+ 	*bti2c = 2;			/* lower data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 0;			/* lower clock */
+ 	DELAY( I2C_LDELAY );
+ }
+ 
+ /*
+  * stop an I2C bus transaction
+  */
+ static void
+ i2cStop( volatile u_long* bti2c )
+ {
+ 	*bti2c = 0;			/* lower clock & data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 2;			/* raise clock */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 3;			/* clock hi, raise data */
+ 	DELAY( I2C_LDELAY );
+ }
+ 
+ /*
+  * place a '1' bit on the I2C bus
+  */
+ static void
+ i2cHi( volatile u_long* bti2c )
+ {
+ 	*bti2c = 1;			/* raise data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 3;			/* data hi, raise clock */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 1;			/* lower clock */
+ 	DELAY( I2C_LDELAY );
+ }
+ 
+ /*
+  * place a '0' bit on the I2C bus
+  */
+ static void
+ i2cLo( volatile u_long* bti2c )
+ {
+ 	*bti2c = 0;			/* lower data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 2;			/* data lo, raise clock */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 0;			/* lower clock */
+ 	DELAY( I2C_LDELAY );
+ }
+ 
+ /*
+  * do the 'ACK' thing with the slave
+  */
+ static int
+ i2cAck( volatile u_long* bti2c )
+ {
+ 	int acknowledge;
+ 
+ 	*bti2c = 1;			/* release data */
+ 	DELAY( I2C_LDELAY );
+ 	*bti2c = 3;			/* release clock */
+ 	DELAY( I2C_LDELAY );
+ 
+         acknowledge = *bti2c & 1;	/* read ACK bit */
+ 
+ 	*bti2c = 1;			/* lower clock */
+ 	DELAY( I2C_LDELAY );
+ 
+ 	return acknowledge;
+ }
+ 
+ /*
+  * read a byte from the I2C bus
+  */
+ static int
+ i2cRead( volatile u_long* bti2c )
+ {
+ 	int x;
+         int byte;
+ 
+ 	*bti2c = 1;			/* raise data */
+ 	DELAY( I2C_SDELAY );
+ 
+         for ( byte = 0, x = 7; x >= 0; --x )
+         {
+ 		*bti2c = 3;		/* data hi, raise clock */
+ 		DELAY( I2C_SDELAY );
+ 
+ 		if ( *bti2c & 1 )	/* read data */
+ 			byte |= (1<<x);
+ 
+ 		*bti2c = 1;		/* lower clock */
+ 		DELAY( I2C_SDELAY );
+         }
+ 
+         i2cHi( bti2c );			/* ??? */
+ 
+         return byte;
+ }
+ 
+ /*
+  * write a byte to the I2C bus
+  */
+ static int
+ i2cWrite( volatile u_long* bti2c, u_char byte )
+ {
+ 	int x;
+ 
+ 	*bti2c = 0;			/* lower data & clock */
+ 
+         for ( x = 7; x >= 0; --x )
+ 		(byte & (1<<x)) ? i2cHi( bti2c ) : i2cLo( bti2c );
+ 
+         return i2cAck( bti2c );
+ }
+ 
+ 
+ /*
+  * set the frequency of the tuner
+  */
+ static int
+ tv_freq( bktr_reg_t* bktr, int frequency )
+ {
+ 	volatile u_long*	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);
+ 
+         /* send the data to the TSA5522 */
+         bti2c = (u_long*)&bktr->base[ BKTR_I2C_CONTROL ];
+ 
+         disable_intr();
+         i2cStart( bti2c );
+ 
+         i2cWrite( bti2c, TSA5522_ADDR );	/* the I2C address */
+ 
+         /* the data sheet wants the order set according to direction */
+         if ( frequency > bktr->tuner.frequency )
+         {
+ 	        i2cWrite( bti2c, (N >> 8) & 0x7f );
+         	i2cWrite( bti2c, N & 0xff );
+ 	        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 );
+         	i2cWrite( bti2c, N & 0xff );
+         }
+ 
+         i2cStop( bti2c );
+         enable_intr();
+ 
+         return 0;
+ }
+ 
+ 
+ /*
+  * North American Broadcast Channels:
+  *
+  * Chnl Freq
+  *  2	 5525
+  *  3	 6125
+  *  4	 6725
+  * 
+  *  5	 7725
+  *  6	 8325
+  * 
+  *  7	17525
+  * 13	21125
+  * 
+  * 14	47125
+  * 83	88525
+  */
+ static int
+ frequency_nabcst( int channel )
+ {
+         if ( channel > 83 )
+ 		return -1;
+ 
+         if ( channel >= 14 )
+ 		return 47125 + ((channel-14) * 600 );
+ 
+         else if ( channel >= 7 )
+ 		return 17525 + ((channel-7) * 600 );
+ 
+ 	else
+ 		switch( channel )
+ 	        {
+         	case 2:
+ 	            return 5525;
+ 	        case 3:
+         	    return 6125;
+ 	        case 4:
+         	    return 6725;
+ 	        case 5:
+         	    return 7725;
+ 	        case 6:
+         	    return 8325;
+ 	        }
+ 
+         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;
+ 
+ 	/* FIXME: */
+         case TUNERTYPE_CABLEIRC:
+         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;
+ }
+ 
+ #endif /* TUNER */
  
  
  #if !defined(METEOR_FreeBSD_210)	/* XXX */
-------------------------------------- cut ------------------------------------

-------------------------------------- cut ------------------------------------

*** tv.c	1997/02/28 02:23:51	1.1
--- tv.c	1997/02/27 07:10:28
***************
*** 312,322 ****
                                  paused     = True,
                                  ch;
  
  	mode        = NTSC_MODE;  /* default */
  	geo.columns = NTSC_COLS;
  	geo.rows    = NTSC_ROWS;
  
!         while ((ch = getopt(ac, av, "ePpNnw:h:b:")) != EOF)
  	    switch( tolower(ch) ) {
  	    default:  /* usage */
  fprintf(stderr,"Usage: tv [opts]\n"
--- 312,324 ----
                                  paused     = True,
                                  ch;
  
+ 	int			channel = 2;
+ 
  	mode        = NTSC_MODE;  /* default */
  	geo.columns = NTSC_COLS;
  	geo.rows    = NTSC_ROWS;
  
!         while ((ch = getopt(ac, av, "ePpNnw:h:b:c:")) != EOF)
  	    switch( tolower(ch) ) {
  	    default:  /* usage */
  fprintf(stderr,"Usage: tv [opts]\n"
***************
*** 327,332 ****
--- 329,337 ----
  "	-b %%	: brightness enhance (0.0 = no change)\n"
  );
  		exit(0);
+ 	    case 'c':
+ 		channel = atoi( optarg );
+ 		break;
  	    case 'p': /* pal */
  		mode        = PAL_MODE;
  		geo.columns = PAL_COLS;
***************
*** 433,443 ****
  
  	}
  
! 	i = METEOR_INPUT_DEV0;
          if (ioctl(video, METEORSINPUT, &i) < 0) {
  		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
  		goto bybye;
  
  	}
  
  	XSync(display, False);
--- 438,454 ----
  
  	}
  
! 	i = METEOR_INPUT_DEV1;
          if (ioctl(video, METEORSINPUT, &i) < 0) {
  		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
  		goto bybye;
  
+ 	}
+ 
+ 	i = channel;
+         if (ioctl(video, TVTUNER_SETCHNL, &i) < 0) {
+ 		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
+ 		goto bybye;
  	}
  
  	XSync(display, False);
-------------------------------------- cut ------------------------------------

--
Steve Passe	| powered by
smp@csn.net	|            FreeBSD




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199702280241.TAA00216>