1119418Sobrien/*-
223599Smarkm * 1. Redistributions of source code must retain the
351694Sroger * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
423599Smarkm * All rights reserved.
523599Smarkm *
623599Smarkm * Redistribution and use in source and binary forms, with or without
723599Smarkm * modification, are permitted provided that the following conditions
823599Smarkm * are met:
923599Smarkm * 1. Redistributions of source code must retain the above copyright
1023599Smarkm *    notice, this list of conditions and the following disclaimer.
1123599Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1223599Smarkm *    notice, this list of conditions and the following disclaimer in the
1323599Smarkm *    documentation and/or other materials provided with the distribution.
1423599Smarkm * 3. All advertising materials mentioning features or use of this software
1523599Smarkm *    must display the following acknowledgement:
1651694Sroger *	This product includes software developed by Amancio Hasty and
1751694Sroger *      Roger Hardiman
1823599Smarkm * 4. The name of the author may not be used to endorse or promote products
1923599Smarkm *    derived from this software without specific prior written permission.
2023599Smarkm *
2123599Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2223599Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2323599Smarkm * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2423599Smarkm * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2523599Smarkm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2623599Smarkm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2723599Smarkm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2823599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2923599Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3023599Smarkm * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3123599Smarkm * POSSIBILITY OF SUCH DAMAGE.
3223599Smarkm */
33119418Sobrien/*-
3423599Smarkm * 1. Redistributions of source code must retain the
3523599Smarkm * Copyright (c) 1995 Mark Tinguely and Jim Lowe
3623599Smarkm * All rights reserved.
3723599Smarkm *
3823599Smarkm * Redistribution and use in source and binary forms, with or without
3923599Smarkm * modification, are permitted provided that the following conditions
4023599Smarkm * are met:
4123599Smarkm * 1. Redistributions of source code must retain the above copyright
4223599Smarkm *    notice, this list of conditions and the following disclaimer.
4323599Smarkm * 2. Redistributions in binary form must reproduce the above copyright
4423599Smarkm *    notice, this list of conditions and the following disclaimer in the
4523599Smarkm *    documentation and/or other materials provided with the distribution.
4623599Smarkm * 3. All advertising materials mentioning features or use of this software
4723599Smarkm *    must display the following acknowledgement:
4823599Smarkm *	This product includes software developed by Mark Tinguely and Jim Lowe
4923599Smarkm * 4. The name of the author may not be used to endorse or promote products
5023599Smarkm *    derived from this software without specific prior written permission.
5123599Smarkm *
5223599Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
5323599Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5423599Smarkm * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5523599Smarkm * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
5623599Smarkm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5723599Smarkm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5823599Smarkm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5923599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
6023599Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
6123599Smarkm * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6223599Smarkm * POSSIBILITY OF SUCH DAMAGE.
6323599Smarkm */
6423599Smarkm
65119418Sobrien#include <sys/cdefs.h>
66119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/bktr/bktr_core.c 261455 2014-02-04 03:36:42Z eadler $");
67119418Sobrien
68119418Sobrien/*
69119418Sobrien * This is part of the Driver for Video Capture Cards (Frame grabbers)
70119418Sobrien * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
71119418Sobrien * chipset.
72119418Sobrien * Copyright Roger Hardiman and Amancio Hasty.
73119418Sobrien *
74119418Sobrien * bktr_core : This deals with the Bt848/849/878/879 PCI Frame Grabber,
75119418Sobrien *               Handles all the open, close, ioctl and read userland calls.
76119418Sobrien *               Sets the Bt848 registers and generates RISC pograms.
77119418Sobrien *               Controls the i2c bus and GPIO interface.
78119418Sobrien *               Contains the interface to the kernel.
79119418Sobrien *               (eg probe/attach and open/close/ioctl)
80119418Sobrien */
81119418Sobrien
82119418Sobrien /*
83119418Sobrien   The Brooktree BT848 Driver driver is based upon Mark Tinguely and
84119418Sobrien   Jim Lowe's driver for the Matrox Meteor PCI card . The
85119418Sobrien   Philips SAA 7116 and SAA 7196 are very different chipsets than
86119418Sobrien   the BT848.
87119418Sobrien
88119418Sobrien   The original copyright notice by Mark and Jim is included mostly
89119418Sobrien   to honor their fantastic work in the Matrox Meteor driver!
90119418Sobrien */
91119418Sobrien
9259014Sroger#include "opt_bktr.h"		/* Include any kernel config options */
9323599Smarkm
9448781Sroger#if (                                                            \
95100431Speter       (defined(__FreeBSD__))                                    \
9648781Sroger    || (defined(__bsdi__))                                       \
9748781Sroger    || (defined(__OpenBSD__))                                    \
9848781Sroger    || (defined(__NetBSD__))                                     \
9948781Sroger    )
10046877Sroger
10162214Sroger
10262214Sroger/*******************/
10362214Sroger/* *** FreeBSD *** */
10462214Sroger/*******************/
10562214Sroger#ifdef __FreeBSD__
10662214Sroger
10723599Smarkm#include <sys/param.h>
10823599Smarkm#include <sys/systm.h>
10923599Smarkm#include <sys/kernel.h>
110139917Simp#include <sys/fcntl.h>
11176166Smarkm#include <sys/lock.h>
112254025Sjeff#include <sys/malloc.h>
11376166Smarkm#include <sys/mutex.h>
11473930Sjhb#include <sys/proc.h>
11523599Smarkm#include <sys/signalvar.h>
116139917Simp#include <sys/selinfo.h>
117139917Simp#include <sys/uio.h>
11823599Smarkm
11923599Smarkm#include <vm/vm.h>
12023599Smarkm#include <vm/vm_kern.h>
12123599Smarkm#include <vm/pmap.h>
12223599Smarkm#include <vm/vm_extern.h>
12323599Smarkm
12450693Sroger#include <sys/bus.h>		/* used by smbus and newbus */
12548781Sroger
12667306Sroger#if (__FreeBSD_version < 500000)
12767306Sroger#include <machine/clock.h>              /* for DELAY */
12873930Sjhb#define	PROC_LOCK(p)
12973930Sjhb#define	PROC_UNLOCK(p)
130119277Simp#include <pci/pcivar.h>
131119277Simp#else
132119277Simp#include <dev/pci/pcivar.h>
13367306Sroger#endif
13467306Sroger
13559014Sroger#include <machine/bus.h>
13659014Sroger#include <sys/bus.h>
13759014Sroger
138123291Sobrien#include <dev/bktr/ioctl_meteor.h>
139123291Sobrien#include <dev/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
14051537Sroger#include <dev/bktr/bktr_reg.h>
14151694Sroger#include <dev/bktr/bktr_tuner.h>
14251694Sroger#include <dev/bktr/bktr_card.h>
14351694Sroger#include <dev/bktr/bktr_audio.h>
14459014Sroger#include <dev/bktr/bktr_os.h>
14551694Sroger#include <dev/bktr/bktr_core.h>
14665692Sroger#if defined(BKTR_FREEBSD_MODULE)
14765692Sroger#include <dev/bktr/bktr_mem.h>
14865692Sroger#endif
14948781Sroger
15065692Sroger#if defined(BKTR_USE_FREEBSD_SMBUS)
15151537Sroger#include <dev/bktr/bktr_i2c.h>
15250693Sroger#include <dev/smbus/smbconf.h>
15350693Sroger#include <dev/iicbus/iiconf.h>
15450693Sroger#include "smbus_if.h"
15550693Sroger#include "iicbus_if.h"
15646877Sroger#endif
15748781Sroger
15862112Srogerconst char *
15962112Srogerbktr_name(bktr_ptr_t bktr)
16062112Sroger{
16162112Sroger  return bktr->bktr_xname;
16262112Sroger}
16323599Smarkm
16462112Sroger
16529233Smarkm#endif  /* __FreeBSD__ */
16629233Smarkm
16748781Sroger
16850693Sroger/****************/
16950693Sroger/* *** BSDI *** */
17050693Sroger/****************/
17150693Sroger#ifdef __bsdi__
17273930Sjhb#define	PROC_LOCK(p)
17373930Sjhb#define	PROC_UNLOCK(p)
17450693Sroger#endif /* __bsdi__ */
17550693Sroger
17650693Sroger
17750693Sroger/**************************/
17850693Sroger/* *** OpenBSD/NetBSD *** */
17950693Sroger/**************************/
18050693Sroger#if defined(__NetBSD__) || defined(__OpenBSD__)
18159014Sroger
18262214Sroger#include <sys/param.h>
18362214Sroger#include <sys/systm.h>
18462214Sroger#include <sys/kernel.h>
18562214Sroger#include <sys/signalvar.h>
18662214Sroger#include <sys/vnode.h>
18762214Sroger
18862214Sroger#ifdef __NetBSD__
18962214Sroger#include <uvm/uvm_extern.h>
19062214Sroger#else
19162214Sroger#include <vm/vm.h>
19262214Sroger#include <vm/vm_kern.h>
19362214Sroger#include <vm/pmap.h>
19462214Sroger#include <vm/vm_extern.h>
19562214Sroger#endif
19662214Sroger
19759014Sroger#include <sys/inttypes.h>		/* uintptr_t */
19862112Sroger#include <dev/ic/bt8xx.h>
19962112Sroger#include <dev/pci/bktr/bktr_reg.h>
20062112Sroger#include <dev/pci/bktr/bktr_tuner.h>
20162112Sroger#include <dev/pci/bktr/bktr_card.h>
20262112Sroger#include <dev/pci/bktr/bktr_audio.h>
20362112Sroger#include <dev/pci/bktr/bktr_core.h>
20462112Sroger#include <dev/pci/bktr/bktr_os.h>
20559014Sroger
20659014Srogerstatic int bt848_format = -1;
20759014Sroger
20862112Srogerconst char *
20962112Srogerbktr_name(bktr_ptr_t bktr)
21062112Sroger{
21162112Sroger        return (bktr->bktr_dev.dv_xname);
21262112Sroger}
21362112Sroger
21473930Sjhb#define	PROC_LOCK(p)
21573930Sjhb#define	PROC_UNLOCK(p)
21673930Sjhb
21750693Sroger#endif /* __NetBSD__ || __OpenBSD__ */
21850693Sroger
21950693Sroger
22025329Sfsmptypedef u_char bool_t;
22123599Smarkm
22230193Smarkm#define BKTRPRI (PZERO+8)|PCATCH
22350693Sroger#define VBIPRI  (PZERO-4)|PCATCH
22423599Smarkm
22525329Sfsmp
22624528Sfsmp/*
22724528Sfsmp * memory allocated for DMA programs
22824528Sfsmp */
22924528Sfsmp#define DMA_PROG_ALLOC		(8 * PAGE_SIZE)
23024528Sfsmp
23125329Sfsmp/* When to split a dma transfer , the bt848 has timing as well as
23225329Sfsmp   dma transfer size limitations so that we have to split dma
23325329Sfsmp   transfers into two dma requests
23425329Sfsmp   */
23525329Sfsmp#define DMA_BT848_SPLIT 319*2
23625329Sfsmp
23723599Smarkm/*
23823599Smarkm * Allocate enough memory for:
23923599Smarkm *	768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages
24023599Smarkm *
24129233Smarkm * You may override this using the options "BROOKTREE_ALLOC_PAGES=value"
24229233Smarkm * in your  kernel configuration file.
24323599Smarkm */
24429233Smarkm
24523599Smarkm#ifndef BROOKTREE_ALLOC_PAGES
24624087Sfsmp#define BROOKTREE_ALLOC_PAGES	217*4
24723599Smarkm#endif
24824087Sfsmp#define BROOKTREE_ALLOC		(BROOKTREE_ALLOC_PAGES * PAGE_SIZE)
24923599Smarkm
25046176Sroger/* Definitions for VBI capture.
25146176Sroger * There are 16 VBI lines in a PAL video field (32 in a frame),
25246176Sroger * and we take 2044 samples from each line (placed in a 2048 byte buffer
25346176Sroger * for alignment).
25446176Sroger * VBI lines are held in a circular buffer before being read by a
25546176Sroger * user program from /dev/vbi.
25646176Sroger */
25746176Sroger
25846176Sroger#define MAX_VBI_LINES	      16   /* Maximum for all vidoe formats */
25946176Sroger#define VBI_LINE_SIZE         2048 /* Store upto 2048 bytes per line */
26046176Sroger#define VBI_BUFFER_ITEMS      20   /* Number of frames we buffer */
26146176Sroger#define VBI_DATA_SIZE         (VBI_LINE_SIZE * MAX_VBI_LINES * 2)
26246176Sroger#define VBI_BUFFER_SIZE       (VBI_DATA_SIZE * VBI_BUFFER_ITEMS)
26346176Sroger
26446176Sroger
26530980Smarkm/*  Defines for fields  */
26630980Smarkm#define ODD_F  0x01
26730980Smarkm#define EVEN_F 0x02
26830980Smarkm
26946176Sroger
27023599Smarkm/*
27124528Sfsmp * Parameters describing size of transmitted image.
27224246Sfsmp */
27324246Sfsmp
27425329Sfsmpstatic struct format_params format_params[] = {
27530856Seivind/* # define BT848_IFORM_F_AUTO             (0x0) - don't matter. */
27646176Sroger  { 525, 26, 480,  910, 135, 754, 640,  780, 30, 0x68, 0x5d, BT848_IFORM_X_AUTO,
27748781Sroger    12,  1600 },
27830856Seivind/* # define BT848_IFORM_F_NTSCM            (0x1) */
27946176Sroger  { 525, 26, 480,  910, 135, 754, 640,  780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
28048781Sroger    12, 1600 },
28130856Seivind/* # define BT848_IFORM_F_NTSCJ            (0x2) */
28246176Sroger  { 525, 22, 480,  910, 135, 754, 640,  780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
28348781Sroger    12, 1600 },
28430856Seivind/* # define BT848_IFORM_F_PALBDGHI         (0x3) */
28546176Sroger  { 625, 32, 576, 1135, 186, 924, 768,  944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
28646176Sroger    16,  2044 },
28730856Seivind/* # define BT848_IFORM_F_PALM             (0x4) */
28846176Sroger  { 525, 22, 480,  910, 135, 754, 640,  780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
28948781Sroger    12, 1600 },
29030856Seivind/* # define BT848_IFORM_F_PALN             (0x5) */
29146176Sroger  { 625, 32, 576, 1135, 186, 924, 768,  944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
29246176Sroger    16, 2044 },
29330856Seivind/* # define BT848_IFORM_F_SECAM            (0x6) */
29448781Sroger  { 625, 32, 576, 1135, 186, 924, 768,  944, 25, 0x7f, 0xa0, BT848_IFORM_X_XT1,
29546176Sroger    16, 2044 },
29630856Seivind/* # define BT848_IFORM_F_RSVD             (0x7) - ???? */
29746176Sroger  { 625, 32, 576, 1135, 186, 924, 768,  944, 25, 0x7f, 0x72, BT848_IFORM_X_XT0,
29846176Sroger    16, 2044 },
29924528Sfsmp};
30024528Sfsmp
30125329Sfsmp/*
30225329Sfsmp * Table of supported Pixel Formats
30325329Sfsmp */
30425329Sfsmp
30525329Sfsmpstatic struct meteor_pixfmt_internal {
30625329Sfsmp	struct meteor_pixfmt public;
30725329Sfsmp	u_int                color_fmt;
30825329Sfsmp} pixfmt_table[] = {
30925329Sfsmp
31025329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 2, {   0x7c00,  0x03e0,  0x001f }, 0,0 }, 0x33 },
31125329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 2, {   0x7c00,  0x03e0,  0x001f }, 1,0 }, 0x33 },
31225329Sfsmp
31325329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 2, {   0xf800,  0x07e0,  0x001f }, 0,0 }, 0x22 },
31425329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 2, {   0xf800,  0x07e0,  0x001f }, 1,0 }, 0x22 },
31525329Sfsmp
31625329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 3, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x11 },
31725329Sfsmp
31825329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,0 }, 0x00 },
31925329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x00 },
32025329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x00 },
32125329Sfsmp{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x00 },
32229233Smarkm{ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
32329233Smarkm{ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x44 },
32431186Sahasty{ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
32525329Sfsmp
32625329Sfsmp};
32725329Sfsmp#define PIXFMT_TABLE_SIZE ( sizeof(pixfmt_table) / sizeof(pixfmt_table[0]) )
32825329Sfsmp
32925329Sfsmp/*
33025329Sfsmp * Table of Meteor-supported Pixel Formats (for SETGEO compatibility)
33125329Sfsmp */
33225329Sfsmp
33325329Sfsmp/*  FIXME:  Also add YUV_422 and YUV_PACKED as well  */
33425329Sfsmpstatic struct {
33525329Sfsmp	u_long               meteor_format;
33625329Sfsmp	struct meteor_pixfmt public;
33725329Sfsmp} meteor_pixfmt_table[] = {
33833025Sahasty    { METEOR_GEO_YUV_12,
33933025Sahasty      { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
34033025Sahasty    },
34125329Sfsmp
34225329Sfsmp      /* FIXME: Should byte swap flag be on for this one; negative in drvr? */
34329233Smarkm    { METEOR_GEO_YUV_422,
34429233Smarkm      { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
34529233Smarkm    },
34629233Smarkm    { METEOR_GEO_YUV_PACKED,
34729233Smarkm      { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }
34829233Smarkm    },
34925329Sfsmp    { METEOR_GEO_RGB16,
35025329Sfsmp      { 0, METEOR_PIXTYPE_RGB, 2, {   0x7c00,   0x03e0,   0x001f }, 0, 0 }
35125329Sfsmp    },
35225329Sfsmp    { METEOR_GEO_RGB24,
35325329Sfsmp      { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000, 0x00ff00, 0x0000ff }, 0, 0 }
35425329Sfsmp    },
35531186Sahasty
35625329Sfsmp};
35725329Sfsmp#define METEOR_PIXFMT_TABLE_SIZE ( sizeof(meteor_pixfmt_table) / \
35825329Sfsmp				   sizeof(meteor_pixfmt_table[0]) )
35925329Sfsmp
36025329Sfsmp
36125329Sfsmp#define BSWAP (BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN)
36225329Sfsmp#define WSWAP (BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN)
36325329Sfsmp
36425329Sfsmp
36524528Sfsmp
36624528Sfsmp/* sync detect threshold */
36729233Smarkm#if 0
36824528Sfsmp#define SYNC_LEVEL		(BT848_ADC_RESERVED |	\
36924528Sfsmp				 BT848_ADC_CRUSH)	/* threshold ~125 mV */
37024246Sfsmp#else
37124528Sfsmp#define SYNC_LEVEL		(BT848_ADC_RESERVED |	\
37224528Sfsmp				 BT848_ADC_SYNC_T)	/* threshold ~75 mV */
37324246Sfsmp#endif
37424246Sfsmp
37524246Sfsmp
37624528Sfsmp
37736090Sahasty
37824528Sfsmp/* debug utility for holding previous INT_STAT contents */
37924528Sfsmp#define STATUS_SUM
38024528Sfsmpstatic u_long	status_sum = 0;
38124528Sfsmp
38224246Sfsmp/*
38324528Sfsmp * defines to make certain bit-fiddles understandable
38424528Sfsmp */
38524528Sfsmp#define FIFO_ENABLED		BT848_DMA_CTL_FIFO_EN
38624528Sfsmp#define RISC_ENABLED		BT848_DMA_CTL_RISC_EN
38724528Sfsmp#define FIFO_RISC_ENABLED	(BT848_DMA_CTL_FIFO_EN | BT848_DMA_CTL_RISC_EN)
38824528Sfsmp#define FIFO_RISC_DISABLED	0
38924528Sfsmp
39024528Sfsmp#define ALL_INTS_DISABLED	0
39124528Sfsmp#define ALL_INTS_CLEARED	0xffffffff
39224528Sfsmp#define CAPTURE_OFF		0
39324528Sfsmp
39424528Sfsmp#define BIT_SEVEN_HIGH		(1<<7)
39524528Sfsmp#define BIT_EIGHT_HIGH		(1<<8)
39624528Sfsmp
39724528Sfsmp#define I2C_BITS		(BT848_INT_RACK | BT848_INT_I2CDONE)
39830980Smarkm#define TDEC_BITS               (BT848_INT_FDSR | BT848_INT_FBUS)
39924528Sfsmp
40024528Sfsmp
40124528Sfsmp
40248781Srogerstatic int		oformat_meteor_to_bt( u_long format );
40348781Sroger
40448781Srogerstatic u_int		pixfmt_swap_flags( int pixfmt );
40548781Sroger
40624087Sfsmp/*
40724087Sfsmp * bt848 RISC programming routines.
40824087Sfsmp */
40929233Smarkm#ifdef BT848_DUMP
41059014Srogerstatic int	dump_bt848( bktr_ptr_t bktr );
41129233Smarkm#endif
41224087Sfsmp
41324528Sfsmpstatic void	yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols,
41424528Sfsmp			      int rows,  int interlace );
41524528Sfsmpstatic void	yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols,
41624528Sfsmp			     int rows, int interlace );
41733025Sahastystatic void	yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols,
41833025Sahasty			     int rows, int interlace );
41924528Sfsmpstatic void	rgb_prog( bktr_ptr_t bktr, char i_flag, int cols,
42025329Sfsmp			  int rows, int interlace );
42147439Srogerstatic void	rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols,
42247439Sroger			  int rows, int interlace );
42324528Sfsmpstatic void	build_dma_prog( bktr_ptr_t bktr, char i_flag );
42424087Sfsmp
42525329Sfsmpstatic bool_t   getline(bktr_reg_t *, int);
42625329Sfsmpstatic bool_t   notclipped(bktr_reg_t * , int , int);
427139941Scognetstatic bool_t   split(bktr_reg_t *, volatile uint32_t **, int, u_long, int,
42825329Sfsmp		      volatile u_char ** , int  );
42924087Sfsmp
43024528Sfsmpstatic void	start_capture( bktr_ptr_t bktr, unsigned type );
43124528Sfsmpstatic void	set_fps( bktr_ptr_t bktr, u_short fps );
43224087Sfsmp
43324087Sfsmp
43424246Sfsmp
43546176Sroger/*
43643890Sroger * Remote Control Functions
43743890Sroger */
43843890Srogerstatic void	remote_read(bktr_ptr_t bktr, struct bktr_remote *remote);
43943890Sroger
44043890Sroger
44143890Sroger/*
44224528Sfsmp * ioctls common to both video & tuner.
44324246Sfsmp */
44459014Srogerstatic int	common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg );
44524246Sfsmp
44624246Sfsmp
44765692Sroger#if !defined(BKTR_USE_FREEBSD_SMBUS)
44843353Sroger/*
44959014Sroger * i2c primitives for low level control of i2c bus. Added for MSP34xx control
45043353Sroger */
45143353Srogerstatic void     i2c_start( bktr_ptr_t bktr);
45243353Srogerstatic void     i2c_stop( bktr_ptr_t bktr);
45343353Srogerstatic int      i2c_write_byte( bktr_ptr_t bktr, unsigned char data);
45443353Srogerstatic int      i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last );
45543353Sroger#endif
45624246Sfsmp
45743353Sroger
45840781Snsouch
45924246Sfsmp/*
46050693Sroger * the common attach code, used by all OS versions.
46124087Sfsmp */
46251694Srogervoid
46348781Srogercommon_bktr_attach( bktr_ptr_t bktr, int unit, u_long pci_id, u_int rev )
46423599Smarkm{
46565692Sroger	vm_offset_t	buf = 0;
46665692Sroger	int		need_to_allocate_memory = 1;
467118819Salex#ifdef BKTR_NEW_MSP34XX_DRIVER
468118819Salex	int 		err;
469118819Salex#endif
47024087Sfsmp
47148781Sroger/***************************************/
47248781Sroger/* *** OS Specific memory routines *** */
47348781Sroger/***************************************/
47448781Sroger#if defined(__NetBSD__) || defined(__OpenBSD__)
47548781Sroger        /* allocate space for dma program */
47662112Sroger        bktr->dma_prog = get_bktr_mem(bktr, &bktr->dm_prog,
47762112Sroger				      DMA_PROG_ALLOC);
47862112Sroger        bktr->odd_dma_prog = get_bktr_mem(bktr, &bktr->dm_oprog,
47962112Sroger					  DMA_PROG_ALLOC);
48023599Smarkm
48162112Sroger	/* allocate space for the VBI buffer */
48262112Sroger	bktr->vbidata  = get_bktr_mem(bktr, &bktr->dm_vbidata,
48362112Sroger				      VBI_DATA_SIZE);
48462112Sroger	bktr->vbibuffer = get_bktr_mem(bktr, &bktr->dm_vbibuffer,
48562112Sroger				       VBI_BUFFER_SIZE);
48662112Sroger
48748781Sroger        /* allocate space for pixel buffer */
48848781Sroger        if ( BROOKTREE_ALLOC )
48948781Sroger                buf = get_bktr_mem(bktr, &bktr->dm_mem, BROOKTREE_ALLOC);
49048781Sroger        else
49148781Sroger                buf = 0;
49247491Sroger#endif
49347491Sroger
49448781Sroger#if defined(__FreeBSD__) || defined(__bsdi__)
49524528Sfsmp
49665692Sroger/* If this is a module, check if there is any currently saved contiguous memory */
49765692Sroger#if defined(BKTR_FREEBSD_MODULE)
49865692Sroger	if (bktr_has_stored_addresses(unit) == 1) {
49965692Sroger		/* recover the addresses */
50065692Sroger		bktr->dma_prog     = bktr_retrieve_address(unit, BKTR_MEM_DMA_PROG);
50165692Sroger		bktr->odd_dma_prog = bktr_retrieve_address(unit, BKTR_MEM_ODD_DMA_PROG);
50265692Sroger		bktr->vbidata      = bktr_retrieve_address(unit, BKTR_MEM_VBIDATA);
50365692Sroger		bktr->vbibuffer    = bktr_retrieve_address(unit, BKTR_MEM_VBIBUFFER);
50465692Sroger		buf                = bktr_retrieve_address(unit, BKTR_MEM_BUF);
50565692Sroger		need_to_allocate_memory = 0;
50665692Sroger	}
50765692Sroger#endif
50848781Sroger
50965692Sroger	if (need_to_allocate_memory == 1) {
51065692Sroger		/* allocate space for dma program */
51165692Sroger		bktr->dma_prog     = get_bktr_mem(unit, DMA_PROG_ALLOC);
51265692Sroger		bktr->odd_dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC);
51365692Sroger
51465692Sroger		/* allocte space for the VBI buffer */
51565692Sroger		bktr->vbidata  = get_bktr_mem(unit, VBI_DATA_SIZE);
51665692Sroger		bktr->vbibuffer = get_bktr_mem(unit, VBI_BUFFER_SIZE);
51765692Sroger
51865692Sroger		/* allocate space for pixel buffer */
51965692Sroger		if ( BROOKTREE_ALLOC )
52065692Sroger			buf = get_bktr_mem(unit, BROOKTREE_ALLOC);
52165692Sroger		else
52265692Sroger			buf = 0;
52365692Sroger	}
52465692Sroger#endif	/* FreeBSD or BSDi */
52565692Sroger
526123088Struckman#ifdef USE_VBIMUTEX
527123088Struckman	mtx_init(&bktr->vbimutex, "bktr vbi lock", NULL, MTX_DEF);
528123088Struckman#endif
52965692Sroger
53065692Sroger/* If this is a module, save the current contiguous memory */
53165692Sroger#if defined(BKTR_FREEBSD_MODULE)
53265692Srogerbktr_store_address(unit, BKTR_MEM_DMA_PROG,     bktr->dma_prog);
53365692Srogerbktr_store_address(unit, BKTR_MEM_ODD_DMA_PROG, bktr->odd_dma_prog);
53465692Srogerbktr_store_address(unit, BKTR_MEM_VBIDATA,      bktr->vbidata);
53565692Srogerbktr_store_address(unit, BKTR_MEM_VBIBUFFER,    bktr->vbibuffer);
53665692Srogerbktr_store_address(unit, BKTR_MEM_BUF,          buf);
53748781Sroger#endif
53823599Smarkm
53965692Sroger
54023599Smarkm	if ( bootverbose ) {
541106519Sjhb		printf("%s: buffer size %d, addr %p\n",
542210010Snwhitehorn			bktr_name(bktr), (int)BROOKTREE_ALLOC,
543106519Sjhb			(void *)(uintptr_t)vtophys(buf));
54423599Smarkm	}
54523599Smarkm
54623599Smarkm	if ( buf != 0 ) {
54747884Sroger		bktr->bigbuf = buf;
54847884Sroger		bktr->alloc_pages = BROOKTREE_ALLOC_PAGES;
54947884Sroger		bzero((caddr_t) bktr->bigbuf, BROOKTREE_ALLOC);
55047884Sroger	} else {
55147884Sroger		bktr->alloc_pages = 0;
55223599Smarkm	}
55347884Sroger
55424046Sfsmp
55547884Sroger	bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE |
55647884Sroger		      METEOR_DEV0 | METEOR_RGB16;
55747884Sroger	bktr->dma_prog_loaded = FALSE;
55847884Sroger	bktr->cols = 640;
55947884Sroger	bktr->rows = 480;
56047884Sroger	bktr->frames = 1;		/* one frame */
56147884Sroger	bktr->format = METEOR_GEO_RGB16;
56247884Sroger	bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
56347884Sroger	bktr->pixfmt_compat = TRUE;
56447884Sroger
56546176Sroger
56646176Sroger	bktr->vbiinsert = 0;
56746176Sroger	bktr->vbistart = 0;
56846176Sroger	bktr->vbisize = 0;
56946176Sroger	bktr->vbiflags = 0;
57048781Sroger
57146176Sroger
57248781Sroger	/* using the pci device id and revision id */
57347884Sroger	/* and determine the card type            */
57467306Sroger	if (PCI_VENDOR(pci_id) == PCI_VENDOR_BROOKTREE)
57567306Sroger	{
57667306Sroger		switch (PCI_PRODUCT(pci_id)) {
57767306Sroger		case PCI_PRODUCT_BROOKTREE_BT848:
57867306Sroger			if (rev == 0x12)
57967306Sroger				bktr->id = BROOKTREE_848A;
58067306Sroger			else
58167306Sroger				bktr->id = BROOKTREE_848;
58267306Sroger			break;
58367306Sroger		case PCI_PRODUCT_BROOKTREE_BT849:
58467306Sroger			bktr->id = BROOKTREE_849A;
58567306Sroger			break;
58667306Sroger		case PCI_PRODUCT_BROOKTREE_BT878:
58767306Sroger			bktr->id = BROOKTREE_878;
58867306Sroger			break;
58967306Sroger		case PCI_PRODUCT_BROOKTREE_BT879:
59067306Sroger			bktr->id = BROOKTREE_879;
59167306Sroger			break;
59267306Sroger		}
59343770Sroger	};
59437611Sahasty
59547884Sroger	bktr->clr_on_start = FALSE;
59637611Sahasty
59724046Sfsmp	/* defaults for the tuner section of the card */
59824528Sfsmp	bktr->tflags = TUNER_INITALIZED;
59924046Sfsmp	bktr->tuner.frequency = 0;
60024046Sfsmp	bktr->tuner.channel = 0;
60124087Sfsmp	bktr->tuner.chnlset = DEFAULT_CHNLSET;
60251356Sroger	bktr->tuner.afc = 0;
60351694Sroger	bktr->tuner.radio_mode = 0;
60424528Sfsmp	bktr->audio_mux_select = 0;
60524528Sfsmp	bktr->audio_mute_state = FALSE;
60636090Sahasty	bktr->bt848_card = -1;
60736090Sahasty	bktr->bt848_tuner = -1;
60836090Sahasty	bktr->reverse_mute = -1;
60959014Sroger	bktr->slow_msp_audio = 0;
61068071Sroger	bktr->msp_use_mono_source = 0;
61168071Sroger        bktr->msp_source_selected = -1;
61268071Sroger	bktr->audio_mux_present = 1;
61324046Sfsmp
614118819Salex#if defined(__FreeBSD__)
615118819Salex#ifdef BKTR_NEW_MSP34XX_DRIVER
616118819Salex	/* get hint on short programming of the msp34xx, so we know */
617118819Salex	/* if the decision what thread to start should be overwritten */
618118819Salex	if ( (err = resource_int_value("bktr", unit, "mspsimple",
619118819Salex			&(bktr->mspsimple)) ) != 0 )
620118819Salex		bktr->mspsimple = -1;	/* fall back to default */
621118819Salex#endif
622118819Salex#endif
623118819Salex
62450693Sroger	probeCard( bktr, TRUE, unit );
62524087Sfsmp
62651694Sroger	/* Initialise any MSP34xx or TDA98xx audio chips */
62751694Sroger	init_audio_devices( bktr );
62843353Sroger
629118819Salex#ifdef BKTR_NEW_MSP34XX_DRIVER
630118819Salex	/* setup the kenrel thread */
631118819Salex	err = msp_attach( bktr );
632118819Salex	if ( err != 0 ) /* error doing kernel thread stuff, disable msp3400c */
633118819Salex		bktr->card.msp3400c = 0;
634118819Salex#endif
635118819Salex
636118819Salex
63723599Smarkm}
63823599Smarkm
63947884Sroger
64046176Sroger/* Copy the vbi lines from 'vbidata' into the circular buffer, 'vbibuffer'.
64146176Sroger * The circular buffer holds 'n' fixed size data blocks.
64246176Sroger * vbisize   is the number of bytes in the circular buffer
64346176Sroger * vbiread   is the point we reading data out of the circular buffer
64446176Sroger * vbiinsert is the point we insert data into the circular buffer
64546176Sroger */
64646176Srogerstatic void vbidecode(bktr_ptr_t bktr) {
64746176Sroger        unsigned char *dest;
64850693Sroger	unsigned int *seq_dest;
64923599Smarkm
65046176Sroger	/* Check if there is room in the buffer to insert the data. */
65146176Sroger	if (bktr->vbisize + VBI_DATA_SIZE > VBI_BUFFER_SIZE) return;
65246176Sroger
65346176Sroger	/* Copy the VBI data into the next free slot in the buffer. */
65446176Sroger	/* 'dest' is the point in vbibuffer where we want to insert new data */
65546176Sroger        dest = (unsigned char *)bktr->vbibuffer + bktr->vbiinsert;
65646176Sroger        memcpy(dest, (unsigned char*)bktr->vbidata, VBI_DATA_SIZE);
65746176Sroger
65850693Sroger	/* Write the VBI sequence number to the end of the vbi data */
65950693Sroger	/* This is used by the AleVT teletext program */
66051694Sroger	seq_dest = (unsigned int *)((unsigned char *)bktr->vbibuffer
66151694Sroger			+ bktr->vbiinsert
66250693Sroger			+ (VBI_DATA_SIZE - sizeof(bktr->vbi_sequence_number)));
66350693Sroger	*seq_dest = bktr->vbi_sequence_number;
66450693Sroger
66550693Sroger	/* And increase the VBI sequence number */
66650693Sroger	/* This can wrap around */
66750693Sroger	bktr->vbi_sequence_number++;
66850693Sroger
66950693Sroger
67046176Sroger	/* Increment the vbiinsert pointer */
67146176Sroger	/* This can wrap around */
67246176Sroger	bktr->vbiinsert += VBI_DATA_SIZE;
67346176Sroger	bktr->vbiinsert = (bktr->vbiinsert % VBI_BUFFER_SIZE);
67446176Sroger
67546176Sroger	/* And increase the amount of vbi data in the buffer */
67646176Sroger	bktr->vbisize = bktr->vbisize + VBI_DATA_SIZE;
67750693Sroger
67846176Sroger}
67946176Sroger
68046176Sroger
68124246Sfsmp/*
68248781Sroger * the common interrupt handler.
68348781Sroger * Returns a 0 or 1 depending on whether the interrupt has handled.
68448781Sroger * In the OS specific section, bktr_intr() is defined which calls this
68548781Sroger * common interrupt handler.
68624246Sfsmp */
68751694Srogerint
68848781Srogercommon_bktr_intr( void *arg )
68924246Sfsmp{
69024528Sfsmp	bktr_ptr_t		bktr;
69124246Sfsmp	u_long			bktr_status;
69224246Sfsmp	u_char			dstatus;
69330980Smarkm	u_long                  field;
69430980Smarkm	u_long                  w_field;
69530980Smarkm	u_long                  req_field;
69623599Smarkm
69724528Sfsmp	bktr = (bktr_ptr_t) arg;
69824246Sfsmp
69924246Sfsmp	/*
70024246Sfsmp	 * check to see if any interrupts are unmasked on this device.  If
70124246Sfsmp	 * none are, then we likely got here by way of being on a PCI shared
70224246Sfsmp	 * interrupt dispatch list.
70324246Sfsmp	 */
70459014Sroger	if (INL(bktr, BKTR_INT_MASK) == ALL_INTS_DISABLED)
70548781Sroger	  	return 0;	/* bail out now, before we do something we
70624246Sfsmp				   shouldn't */
70724246Sfsmp
70824246Sfsmp	if (!(bktr->flags & METEOR_OPEN)) {
70959014Sroger		OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
71059014Sroger		OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
71124246Sfsmp		/* return; ?? */
71224246Sfsmp	}
71324246Sfsmp
71424246Sfsmp	/* record and clear the INTerrupt status bits */
71559014Sroger	bktr_status = INL(bktr, BKTR_INT_STAT);
71659014Sroger	OUTL(bktr, BKTR_INT_STAT, bktr_status & ~I2C_BITS);	/* don't touch i2c */
71724246Sfsmp
71824246Sfsmp	/* record and clear the device status register */
71959014Sroger	dstatus = INB(bktr, BKTR_DSTATUS);
72059014Sroger	OUTB(bktr, BKTR_DSTATUS, 0x00);
72124246Sfsmp
72224528Sfsmp#if defined( STATUS_SUM )
72324246Sfsmp	/* add any new device status or INTerrupt status bits */
72424528Sfsmp	status_sum |= (bktr_status & ~(BT848_INT_RSV0|BT848_INT_RSV1));
72524528Sfsmp	status_sum |= ((dstatus & (BT848_DSTATUS_COF|BT848_DSTATUS_LOF)) << 6);
72624528Sfsmp#endif /* STATUS_SUM */
72762112Sroger	/* printf( "%s: STATUS %x %x %x \n", bktr_name(bktr),
72859014Sroger		dstatus, bktr_status, INL(bktr, BKTR_RISC_COUNT) );
72936090Sahasty	*/
73046176Sroger
73146176Sroger
73224246Sfsmp	/* if risc was disabled re-start process again */
73350693Sroger	/* if there was one of the following errors re-start again */
73424528Sfsmp	if ( !(bktr_status & BT848_INT_RISC_EN) ||
73550693Sroger	     ((bktr_status &(/* BT848_INT_FBUS   | */
73650693Sroger			     /* BT848_INT_FTRGT  | */
73750693Sroger			     /* BT848_INT_FDSR   | */
73824528Sfsmp			      BT848_INT_PPERR  |
73950693Sroger			      BT848_INT_RIPERR | BT848_INT_PABORT |
74050693Sroger			      BT848_INT_OCERR  | BT848_INT_SCERR) ) != 0)
74159014Sroger		|| ((INB(bktr, BKTR_TDEC) == 0) && (bktr_status & TDEC_BITS)) ) {
74224246Sfsmp
74359014Sroger		u_short	tdec_save = INB(bktr, BKTR_TDEC);
74430980Smarkm
74559014Sroger		OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
74659014Sroger		OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
74724246Sfsmp
74859014Sroger		OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
74924246Sfsmp
75059014Sroger		/*  Reset temporal decimation counter  */
75159014Sroger		OUTB(bktr, BKTR_TDEC, 0);
75259014Sroger		OUTB(bktr, BKTR_TDEC, tdec_save);
75330980Smarkm
75430980Smarkm		/*  Reset to no-fields captured state  */
75530980Smarkm		if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
75630980Smarkm			switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
75730980Smarkm			case METEOR_ONLY_ODD_FIELDS:
75830980Smarkm				bktr->flags |= METEOR_WANT_ODD;
75930980Smarkm				break;
76030980Smarkm			case METEOR_ONLY_EVEN_FIELDS:
76130980Smarkm				bktr->flags |= METEOR_WANT_EVEN;
76230980Smarkm				break;
76330980Smarkm			default:
76430980Smarkm				bktr->flags |= METEOR_WANT_MASK;
76530980Smarkm				break;
76630980Smarkm			}
76730980Smarkm		}
76830980Smarkm
76959014Sroger		OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
77059014Sroger		OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
77159014Sroger		OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
77224246Sfsmp
77359014Sroger		OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
77459014Sroger				    BT848_INT_RISCI      |
77559014Sroger				    BT848_INT_VSYNC      |
77659014Sroger				    BT848_INT_FMTCHG);
77724528Sfsmp
77859014Sroger		OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
77948781Sroger		return 1;
78024246Sfsmp	}
78124246Sfsmp
78246176Sroger	/* If this is not a RISC program interrupt, return */
78324528Sfsmp	if (!(bktr_status & BT848_INT_RISCI))
78448781Sroger		return 0;
78546176Sroger
78624528Sfsmp/**
78762112Sroger	printf( "%s: intr status %x %x %x\n", bktr_name(bktr),
78859014Sroger		bktr_status, dstatus, INL(bktr, BKTR_RISC_COUNT) );
78924528Sfsmp */
79024246Sfsmp
79159014Sroger
79224246Sfsmp	/*
79324246Sfsmp	 * Disable future interrupts if a capture mode is not selected.
79424246Sfsmp	 * This can happen when we are in the process of closing or
79524246Sfsmp	 * changing capture modes, otherwise it shouldn't happen.
79624246Sfsmp	 */
79724246Sfsmp	if (!(bktr->flags & METEOR_CAP_MASK))
79859014Sroger		OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
79924246Sfsmp
80050693Sroger
80150693Sroger	/* Determine which field generated this interrupt */
80250693Sroger	field = ( bktr_status & BT848_INT_FIELD ) ? EVEN_F : ODD_F;
80350693Sroger
80450693Sroger
80524246Sfsmp	/*
80654314Sroger	 * Process the VBI data if it is being captured. We do this once
80750693Sroger	 * both Odd and Even VBI data is captured. Therefore we do this
80850693Sroger	 * in the Even field interrupt handler.
80950693Sroger	 */
810123088Struckman	LOCK_VBI(bktr);
81159014Sroger	if (  (bktr->vbiflags & VBI_CAPTURE)
81259014Sroger	    &&(bktr->vbiflags & VBI_OPEN)
81359014Sroger            &&(field==EVEN_F)) {
81450693Sroger		/* Put VBI data into circular buffer */
81550693Sroger               	vbidecode(bktr);
81650693Sroger
81750693Sroger		/* If someone is blocked on reading from /dev/vbi, wake them */
81850693Sroger		if (bktr->vbi_read_blocked) {
81950693Sroger			bktr->vbi_read_blocked = FALSE;
82050693Sroger          	     	wakeup(VBI_SLEEP);
82150693Sroger		}
82250693Sroger
82350693Sroger		/* If someone has a select() on /dev/vbi, inform them */
82492252Salfred		if (SEL_WAITING(&bktr->vbi_select)) {
825122352Stanimura			selwakeuppri(&bktr->vbi_select, VBIPRI);
82650693Sroger		}
82750693Sroger
82850693Sroger
82950693Sroger	}
830123088Struckman	UNLOCK_VBI(bktr);
83150693Sroger
83250693Sroger	/*
83325329Sfsmp	 *  Register the completed field
83430980Smarkm	 *    (For dual-field mode, require fields from the same frame)
83525329Sfsmp	 */
83630980Smarkm	switch ( bktr->flags & METEOR_WANT_MASK ) {
83730980Smarkm		case METEOR_WANT_ODD  : w_field = ODD_F         ;  break;
83830980Smarkm		case METEOR_WANT_EVEN : w_field = EVEN_F        ;  break;
83930980Smarkm		default               : w_field = (ODD_F|EVEN_F);  break;
84030980Smarkm	}
84130980Smarkm	switch ( bktr->flags & METEOR_ONLY_FIELDS_MASK ) {
84230980Smarkm		case METEOR_ONLY_ODD_FIELDS  : req_field = ODD_F  ;  break;
84330980Smarkm		case METEOR_ONLY_EVEN_FIELDS : req_field = EVEN_F ;  break;
84430980Smarkm		default                      : req_field = (ODD_F|EVEN_F);
84530980Smarkm			                       break;
84630980Smarkm	}
84730980Smarkm
84830980Smarkm	if (( field == EVEN_F ) && ( w_field == EVEN_F ))
84925329Sfsmp		bktr->flags &= ~METEOR_WANT_EVEN;
85030980Smarkm	else if (( field == ODD_F ) && ( req_field == ODD_F ) &&
85130980Smarkm		 ( w_field == ODD_F ))
85225329Sfsmp		bktr->flags &= ~METEOR_WANT_ODD;
85330980Smarkm	else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
85430980Smarkm		 ( w_field == (ODD_F|EVEN_F) ))
85530980Smarkm		bktr->flags &= ~METEOR_WANT_ODD;
85630980Smarkm	else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
85730980Smarkm		 ( w_field == ODD_F )) {
85830980Smarkm		bktr->flags &= ~METEOR_WANT_ODD;
85930980Smarkm		bktr->flags |=  METEOR_WANT_EVEN;
86030980Smarkm	}
86130980Smarkm	else {
86230980Smarkm		/*  We're out of sync.  Start over.  */
86330980Smarkm		if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
86430980Smarkm			switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
86530980Smarkm			case METEOR_ONLY_ODD_FIELDS:
86630980Smarkm				bktr->flags |= METEOR_WANT_ODD;
86730980Smarkm				break;
86830980Smarkm			case METEOR_ONLY_EVEN_FIELDS:
86930980Smarkm				bktr->flags |= METEOR_WANT_EVEN;
87030980Smarkm				break;
87130980Smarkm			default:
87230980Smarkm				bktr->flags |= METEOR_WANT_MASK;
87330980Smarkm				break;
87430980Smarkm			}
87530980Smarkm		}
87648781Sroger		return 1;
87730980Smarkm	}
87825329Sfsmp
87925329Sfsmp	/*
88024246Sfsmp	 * If we have a complete frame.
88124246Sfsmp	 */
88224246Sfsmp	if (!(bktr->flags & METEOR_WANT_MASK)) {
88324246Sfsmp		bktr->frames_captured++;
88424246Sfsmp		/*
88524246Sfsmp		 * post the completion time.
88624246Sfsmp		 */
88724246Sfsmp		if (bktr->flags & METEOR_WANT_TS) {
88824246Sfsmp			struct timeval *ts;
88924246Sfsmp
89024246Sfsmp			if ((u_int) bktr->alloc_pages * PAGE_SIZE
89124246Sfsmp			   <= (bktr->frame_size + sizeof(struct timeval))) {
89224246Sfsmp				ts =(struct timeval *)bktr->bigbuf +
89324246Sfsmp				  bktr->frame_size;
89424246Sfsmp				/* doesn't work in synch mode except
89524246Sfsmp				 *  for first frame */
89624246Sfsmp				/* XXX */
89724246Sfsmp				microtime(ts);
89824246Sfsmp			}
89924246Sfsmp		}
90046176Sroger
90124246Sfsmp
90224246Sfsmp		/*
90324246Sfsmp		 * Wake up the user in single capture mode.
90424246Sfsmp		 */
90524246Sfsmp		if (bktr->flags & METEOR_SINGLE) {
90624246Sfsmp
90724246Sfsmp			/* stop dma */
90859014Sroger			OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
90924528Sfsmp
91024528Sfsmp			/* disable risc, leave fifo running */
91159014Sroger			OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
91246176Sroger			wakeup(BKTR_SLEEP);
91324246Sfsmp		}
91424246Sfsmp
91524246Sfsmp		/*
91624246Sfsmp		 * If the user requested to be notified via signal,
91724246Sfsmp		 * let them know the frame is complete.
91824246Sfsmp		 */
91933025Sahasty
920119493Snectar		if (bktr->proc != NULL) {
92173930Sjhb			PROC_LOCK(bktr->proc);
922225617Skmacy			kern_psignal( bktr->proc, bktr->signal);
92373930Sjhb			PROC_UNLOCK(bktr->proc);
92473930Sjhb		}
92524246Sfsmp
92624246Sfsmp		/*
92724246Sfsmp		 * Reset the want flags if in continuous or
92824246Sfsmp		 * synchronous capture mode.
92924246Sfsmp		 */
93029233Smarkm/*
93129233Smarkm* XXX NOTE (Luigi):
93229233Smarkm* currently we only support 3 capture modes: odd only, even only,
93329233Smarkm* odd+even interlaced (odd field first). A fourth mode (non interlaced,
93429233Smarkm* either even OR odd) could provide 60 (50 for PAL) pictures per
93529233Smarkm* second, but it would require this routine to toggle the desired frame
93629233Smarkm* each time, and one more different DMA program for the Bt848.
93729233Smarkm* As a consequence, this fourth mode is currently unsupported.
93829233Smarkm*/
93929233Smarkm
94024528Sfsmp		if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
94124246Sfsmp			switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
94224246Sfsmp			case METEOR_ONLY_ODD_FIELDS:
94324246Sfsmp				bktr->flags |= METEOR_WANT_ODD;
94424246Sfsmp				break;
94524246Sfsmp			case METEOR_ONLY_EVEN_FIELDS:
94624246Sfsmp				bktr->flags |= METEOR_WANT_EVEN;
94724246Sfsmp				break;
94824246Sfsmp			default:
94924246Sfsmp				bktr->flags |= METEOR_WANT_MASK;
95024246Sfsmp				break;
95124246Sfsmp			}
95224246Sfsmp		}
95324246Sfsmp	}
95424246Sfsmp
95548781Sroger	return 1;
95624246Sfsmp}
95724246Sfsmp
95824246Sfsmp
95923599Smarkm
96023599Smarkm
96124046Sfsmp/*
96224046Sfsmp *
96324046Sfsmp */
96451694Srogerextern int bt848_format; /* used to set the default format, PAL or NTSC */
96551694Srogerint
96624528Sfsmpvideo_open( bktr_ptr_t bktr )
96724246Sfsmp{
96837611Sahasty	int frame_rate, video_format=0;
96924246Sfsmp
97023599Smarkm	if (bktr->flags & METEOR_OPEN)		/* device is busy */
97124528Sfsmp		return( EBUSY );
97223599Smarkm
97323599Smarkm	bktr->flags |= METEOR_OPEN;
97424246Sfsmp
97529233Smarkm#ifdef BT848_DUMP
97624087Sfsmp	dump_bt848( bt848 );
97729233Smarkm#endif
97824087Sfsmp
97936090Sahasty        bktr->clr_on_start = FALSE;
98036090Sahasty
98159014Sroger	OUTB(bktr, BKTR_DSTATUS, 0x00);			/* clear device status reg. */
98223599Smarkm
98359014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
98436172Sahasty
985153084Sru#if defined(BKTR_SYSTEM_DEFAULT) && BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL
98637611Sahasty	video_format = 0;
98736172Sahasty#else
98837611Sahasty	video_format = 1;
98936172Sahasty#endif
99036172Sahasty
99137611Sahasty	if (bt848_format == 0 )
99237611Sahasty	  video_format = 0;
99337611Sahasty
99437611Sahasty	if (bt848_format == 1 )
99537611Sahasty	  video_format = 1;
99637611Sahasty
99737611Sahasty	if (video_format == 1 ) {
99859014Sroger	  OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_NTSCM);
99937611Sahasty	  bktr->format_params = BT848_IFORM_F_NTSCM;
100037611Sahasty
100137611Sahasty	} else {
100259014Sroger	  OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_PALBDGHI);
100337611Sahasty	  bktr->format_params = BT848_IFORM_F_PALBDGHI;
100437611Sahasty
100537611Sahasty	}
100637611Sahasty
100759014Sroger	OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | format_params[bktr->format_params].iform_xtsel);
100839041Ssos
100939041Ssos	/* work around for new Hauppauge 878 cards */
101039041Ssos	if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
101143770Sroger	    (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) )
101259014Sroger		OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
101339041Ssos	else
101459014Sroger		OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
101539041Ssos
101659277Sroger	OUTB(bktr, BKTR_ADELAY, format_params[bktr->format_params].adelay);
101759014Sroger	OUTB(bktr, BKTR_BDELAY, format_params[bktr->format_params].bdelay);
101838184Ssos	frame_rate    = format_params[bktr->format_params].frame_rate;
101938184Ssos
102039842Ssos	/* enable PLL mode using 28Mhz crystal for PAL/SECAM users */
102139842Ssos	if (bktr->xtal_pll_mode == BT848_USE_PLL) {
102259014Sroger		OUTB(bktr, BKTR_TGCTRL, 0);
102359014Sroger		OUTB(bktr, BKTR_PLL_F_LO, 0xf9);
102459014Sroger		OUTB(bktr, BKTR_PLL_F_HI, 0xdc);
102559014Sroger		OUTB(bktr, BKTR_PLL_F_XCI, 0x8e);
102639842Ssos	}
102738707Ssos
102836663Sahasty	bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0;
102936663Sahasty
103025329Sfsmp	bktr->max_clip_node = 0;
103123599Smarkm
103259014Sroger	OUTB(bktr, BKTR_COLOR_CTL, BT848_COLOR_CTL_GAMMA | BT848_COLOR_CTL_RGB_DED);
103325329Sfsmp
103459014Sroger	OUTB(bktr, BKTR_E_HSCALE_LO, 170);
103559014Sroger	OUTB(bktr, BKTR_O_HSCALE_LO, 170);
103623599Smarkm
103759014Sroger	OUTB(bktr, BKTR_E_DELAY_LO, 0x72);
103859014Sroger	OUTB(bktr, BKTR_O_DELAY_LO, 0x72);
103959014Sroger	OUTB(bktr, BKTR_E_SCLOOP, 0);
104059014Sroger	OUTB(bktr, BKTR_O_SCLOOP, 0);
104123599Smarkm
104259014Sroger	OUTB(bktr, BKTR_VBI_PACK_SIZE, 0);
104359014Sroger	OUTB(bktr, BKTR_VBI_PACK_DEL, 0);
104423599Smarkm
104523599Smarkm	bktr->fifo_errors = 0;
104623599Smarkm	bktr->dma_errors = 0;
104723599Smarkm	bktr->frames_captured = 0;
104823599Smarkm	bktr->even_fields_captured = 0;
104923599Smarkm	bktr->odd_fields_captured = 0;
105073930Sjhb	bktr->proc = NULL;
105136172Sahasty	set_fps(bktr, frame_rate);
105223599Smarkm	bktr->video.addr = 0;
105323599Smarkm	bktr->video.width = 0;
105423599Smarkm	bktr->video.banksize = 0;
105523599Smarkm	bktr->video.ramsize = 0;
105625497Sjmg	bktr->pixfmt_compat = TRUE;
105725497Sjmg	bktr->format = METEOR_GEO_RGB16;
105825497Sjmg	bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
105923599Smarkm
106038706Ssos	bktr->capture_area_enabled = FALSE;
106138706Ssos
106259014Sroger	OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT);	/* if you take this out triton
106337611Sahasty                                                   based motherboards will
106437611Sahasty						   operate unreliably */
106524246Sfsmp	return( 0 );
106624246Sfsmp}
106724246Sfsmp
106851694Srogerint
106946176Srogervbi_open( bktr_ptr_t bktr )
107046176Sroger{
1071123088Struckman
1072123088Struckman	LOCK_VBI(bktr);
1073123088Struckman
1074123088Struckman	if (bktr->vbiflags & VBI_OPEN) {	/* device is busy */
1075123088Struckman		UNLOCK_VBI(bktr);
107646176Sroger		return( EBUSY );
1077123088Struckman	}
107824246Sfsmp
107946176Sroger	bktr->vbiflags |= VBI_OPEN;
108046176Sroger
108146176Sroger	/* reset the VBI circular buffer pointers and clear the buffers */
108246176Sroger	bktr->vbiinsert = 0;
108346176Sroger	bktr->vbistart = 0;
108446176Sroger	bktr->vbisize = 0;
108550693Sroger	bktr->vbi_sequence_number = 0;
108650693Sroger	bktr->vbi_read_blocked = FALSE;
108746176Sroger
108846176Sroger	bzero((caddr_t) bktr->vbibuffer, VBI_BUFFER_SIZE);
108946176Sroger	bzero((caddr_t) bktr->vbidata,  VBI_DATA_SIZE);
109046176Sroger
1091123088Struckman	UNLOCK_VBI(bktr);
1092123088Struckman
109346176Sroger	return( 0 );
109446176Sroger}
109546176Sroger
109624246Sfsmp/*
109724246Sfsmp *
109824246Sfsmp */
109951694Srogerint
110024528Sfsmptuner_open( bktr_ptr_t bktr )
110124246Sfsmp{
110224528Sfsmp	if ( !(bktr->tflags & TUNER_INITALIZED) )	/* device not found */
110324528Sfsmp		return( ENXIO );
110424246Sfsmp
110524528Sfsmp	if ( bktr->tflags & TUNER_OPEN )		/* already open */
110624528Sfsmp		return( 0 );
110724246Sfsmp
110824528Sfsmp	bktr->tflags |= TUNER_OPEN;
110951356Sroger	bktr->tuner.frequency = 0;
111051356Sroger	bktr->tuner.channel = 0;
111151356Sroger	bktr->tuner.chnlset = DEFAULT_CHNLSET;
111251356Sroger	bktr->tuner.afc = 0;
111351694Sroger	bktr->tuner.radio_mode = 0;
111424528Sfsmp
111524528Sfsmp	/* enable drivers on the GPIO port that control the MUXes */
111659014Sroger	OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | bktr->card.gpio_mux_bits);
111724528Sfsmp
111830856Seivind	/* unmute the audio stream */
111924087Sfsmp	set_audio( bktr, AUDIO_UNMUTE );
112024087Sfsmp
112151694Sroger	/* Initialise any audio chips, eg MSP34xx or TDA98xx */
112251694Sroger	init_audio_devices( bktr );
112343353Sroger
112424246Sfsmp	return( 0 );
112523599Smarkm}
112623599Smarkm
112724046Sfsmp
112824246Sfsmp
112923599Smarkm
113024246Sfsmp/*
113124246Sfsmp *
113224246Sfsmp */
113351694Srogerint
113424528Sfsmpvideo_close( bktr_ptr_t bktr )
113524246Sfsmp{
113624528Sfsmp	bktr->flags &= ~(METEOR_OPEN     |
113724528Sfsmp			 METEOR_SINGLE   |
113824528Sfsmp			 METEOR_CAP_MASK |
113924528Sfsmp			 METEOR_WANT_MASK);
114024246Sfsmp
114159014Sroger	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
114259014Sroger	OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
114323599Smarkm
114424528Sfsmp	bktr->dma_prog_loaded = FALSE;
114559014Sroger	OUTB(bktr, BKTR_TDEC, 0);
114659014Sroger	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
114723599Smarkm
114824528Sfsmp/** FIXME: is 0xf magic, wouldn't 0x00 work ??? */
114959014Sroger	OUTL(bktr, BKTR_SRESET, 0xf);
115059014Sroger	OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
115123599Smarkm
115224246Sfsmp	return( 0 );
115324246Sfsmp}
115424246Sfsmp
115524246Sfsmp
115624246Sfsmp/*
115724246Sfsmp * tuner close handle,
115824246Sfsmp *  place holder for tuner specific operations on a close.
115924246Sfsmp */
116051694Srogerint
116124528Sfsmptuner_close( bktr_ptr_t bktr )
116224246Sfsmp{
116324528Sfsmp	bktr->tflags &= ~TUNER_OPEN;
116424246Sfsmp
116524087Sfsmp	/* mute the audio by switching the mux */
116624087Sfsmp	set_audio( bktr, AUDIO_MUTE );
116724087Sfsmp
116824528Sfsmp	/* disable drivers on the GPIO port that control the MUXes */
116959014Sroger	OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) & ~bktr->card.gpio_mux_bits);
117024246Sfsmp
117124246Sfsmp	return( 0 );
117223599Smarkm}
117323599Smarkm
117451694Srogerint
117546176Srogervbi_close( bktr_ptr_t bktr )
117646176Sroger{
117723599Smarkm
1178123088Struckman	LOCK_VBI(bktr);
1179123088Struckman
118046176Sroger	bktr->vbiflags &= ~VBI_OPEN;
118146176Sroger
1182123088Struckman	UNLOCK_VBI(bktr);
1183123088Struckman
118446176Sroger	return( 0 );
118546176Sroger}
118646176Sroger
118723599Smarkm/*
118846176Sroger *
118946176Sroger */
119051694Srogerint
1191130585Sphkvideo_read(bktr_ptr_t bktr, int unit, struct cdev *dev, struct uio *uio)
119246176Sroger{
119346176Sroger        int             status;
119446176Sroger        int             count;
119546176Sroger
119646176Sroger
119723599Smarkm	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
119824528Sfsmp		return( ENOMEM );
119923599Smarkm
120023599Smarkm	if (bktr->flags & METEOR_CAP_MASK)
120124528Sfsmp		return( EIO );	/* already capturing */
120223599Smarkm
120359014Sroger        OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
120433025Sahasty
120533025Sahasty
120625329Sfsmp	count = bktr->rows * bktr->cols *
120725329Sfsmp		pixfmt_table[ bktr->pixfmt ].public.Bpp;
120825329Sfsmp
120923599Smarkm	if ((int) uio->uio_iov->iov_len < count)
121024528Sfsmp		return( EINVAL );
121123599Smarkm
121224528Sfsmp	bktr->flags &= ~(METEOR_CAP_MASK | METEOR_WANT_MASK);
121324528Sfsmp
121433025Sahasty	/* capture one frame */
121533025Sahasty	start_capture(bktr, METEOR_SINGLE);
121633025Sahasty	/* wait for capture to complete */
121759014Sroger	OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
121859014Sroger	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
121959014Sroger	OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
122059014Sroger	OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
122159014Sroger                            BT848_INT_RISCI      |
122259014Sroger                            BT848_INT_VSYNC      |
122359014Sroger                            BT848_INT_FMTCHG);
122423599Smarkm
122533025Sahasty
122646176Sroger	status = tsleep(BKTR_SLEEP, BKTRPRI, "captur", 0);
122723599Smarkm	if (!status)		/* successful capture */
122823599Smarkm		status = uiomove((caddr_t)bktr->bigbuf, count, uio);
122923599Smarkm	else
123062112Sroger		printf ("%s: read: tsleep error %d\n",
123162112Sroger			bktr_name(bktr), status);
123223599Smarkm
123323599Smarkm	bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
123423599Smarkm
123524528Sfsmp	return( status );
123623599Smarkm}
123723599Smarkm
123846176Sroger/*
123946176Sroger * Read VBI data from the vbi circular buffer
124046176Sroger * The buffer holds vbi data blocks which are the same size
124146176Sroger * vbiinsert is the position we will insert the next item into the buffer
124246176Sroger * vbistart is the actual position in the buffer we want to read from
124346176Sroger * vbisize is the exact number of bytes in the buffer left to read
124446176Sroger */
124551694Srogerint
124650693Srogervbi_read(bktr_ptr_t bktr, struct uio *uio, int ioflag)
124746176Sroger{
1248123088Struckman	int             readsize, readsize2, start;
124946176Sroger	int             status;
125023599Smarkm
1251123088Struckman	/*
1252123088Struckman	 * XXX - vbi_read() should be protected against being re-entered
1253123088Struckman	 * while it is unlocked for the uiomove.
1254123088Struckman	 */
1255123088Struckman	LOCK_VBI(bktr);
125646176Sroger
125750693Sroger	while(bktr->vbisize == 0) {
1258139917Simp		if (ioflag & FNDELAY) {
1259123088Struckman			status = EWOULDBLOCK;
1260123088Struckman			goto out;
126150693Sroger		}
126250693Sroger
126350693Sroger		bktr->vbi_read_blocked = TRUE;
1264123088Struckman#ifdef USE_VBIMUTEX
1265123088Struckman		if ((status = msleep(VBI_SLEEP, &bktr->vbimutex, VBIPRI, "vbi",
1266123088Struckman		    0))) {
1267123088Struckman			goto out;
1268123088Struckman		}
1269123088Struckman#else
127050693Sroger		if ((status = tsleep(VBI_SLEEP, VBIPRI, "vbi", 0))) {
1271123088Struckman			goto out;
127250693Sroger		}
1273123088Struckman#endif
127450693Sroger	}
127550693Sroger
127650693Sroger	/* Now we have some data to give to the user */
127750693Sroger
127850693Sroger	/* We cannot read more bytes than there are in
127950693Sroger	 * the circular buffer
128050693Sroger	 */
128146176Sroger	readsize = (int)uio->uio_iov->iov_len;
128246176Sroger
128346176Sroger	if (readsize > bktr->vbisize) readsize = bktr->vbisize;
128446176Sroger
128550693Sroger	/* Check if we can read this number of bytes without having
128650693Sroger	 * to wrap around the circular buffer */
128746176Sroger	if((bktr->vbistart + readsize) >= VBI_BUFFER_SIZE) {
128846176Sroger		/* We need to wrap around */
128946176Sroger
129050693Sroger		readsize2 = VBI_BUFFER_SIZE - bktr->vbistart;
1291123088Struckman		start =  bktr->vbistart;
1292123088Struckman		UNLOCK_VBI(bktr);
1293123088Struckman               	status = uiomove((caddr_t)bktr->vbibuffer + start, readsize2, uio);
1294123088Struckman		if (status == 0)
1295123088Struckman			status = uiomove((caddr_t)bktr->vbibuffer, (readsize - readsize2), uio);
129650693Sroger	} else {
1297123088Struckman		UNLOCK_VBI(bktr);
129846176Sroger		/* We do not need to wrap around */
129950693Sroger		status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize, uio);
130050693Sroger	}
130146176Sroger
1302123088Struckman	LOCK_VBI(bktr);
1303123088Struckman
130446176Sroger	/* Update the number of bytes left to read */
130550693Sroger	bktr->vbisize -= readsize;
130646176Sroger
130746176Sroger	/* Update vbistart */
130850693Sroger	bktr->vbistart += readsize;
130946176Sroger	bktr->vbistart = bktr->vbistart % VBI_BUFFER_SIZE; /* wrap around if needed */
131046176Sroger
1311123088Struckmanout:
1312123088Struckman	UNLOCK_VBI(bktr);
1313123088Struckman
131451694Sroger	return( status );
131546176Sroger
131646176Sroger}
131746176Sroger
131823599Smarkm
131923599Smarkm
132023599Smarkm/*
132124246Sfsmp * video ioctls
132224246Sfsmp */
132351694Srogerint
132483366Sjulianvideo_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td )
132524246Sfsmp{
132624246Sfsmp	volatile u_char		c_temp;
132729233Smarkm	unsigned int		temp;
132835259Sahasty	unsigned int		temp_iform;
132923599Smarkm	unsigned int		error;
133023599Smarkm	struct meteor_geomet	*geo;
133150693Sroger	struct meteor_counts	*counts;
133223599Smarkm	struct meteor_video	*video;
133338706Ssos	struct bktr_capture_area *cap_area;
133423599Smarkm	vm_offset_t		buf;
133525329Sfsmp	int                     i;
1336119493Snectar	int			sig;
133736090Sahasty	char                    char_temp;
133836090Sahasty
133924246Sfsmp	switch ( cmd ) {
134023599Smarkm
134125329Sfsmp	case BT848SCLIP: /* set clip region */
134225329Sfsmp	    bktr->max_clip_node = 0;
134325329Sfsmp	    memcpy(&bktr->clip_list, arg, sizeof(bktr->clip_list));
134425329Sfsmp
134525329Sfsmp	    for (i = 0; i < BT848_MAX_CLIP_NODE; i++) {
134625329Sfsmp		if (bktr->clip_list[i].y_min ==  0 &&
134730980Smarkm		    bktr->clip_list[i].y_max == 0)
134825329Sfsmp		    break;
134925329Sfsmp	    }
135030980Smarkm	    bktr->max_clip_node = i;
135130980Smarkm
135225329Sfsmp	    /* make sure that the list contains a valid clip secquence */
135325329Sfsmp	    /* the clip rectangles should be sorted by x then by y as the
135425329Sfsmp               second order sort key */
135525329Sfsmp
135625329Sfsmp	    /* clip rectangle list is terminated by y_min and y_max set to 0 */
135725329Sfsmp
135825329Sfsmp	    /* to disable clipping set  y_min and y_max to 0 in the first
135925329Sfsmp               clip rectangle . The first clip rectangle is clip_list[0].
136025329Sfsmp             */
136125329Sfsmp
136225329Sfsmp
136325329Sfsmp
136425329Sfsmp	    if (bktr->max_clip_node == 0 &&
136525329Sfsmp		(bktr->clip_list[0].y_min != 0 &&
136625329Sfsmp		 bktr->clip_list[0].y_max != 0)) {
136725329Sfsmp		return EINVAL;
136825329Sfsmp	    }
136925329Sfsmp
137025329Sfsmp	    for (i = 0; i < BT848_MAX_CLIP_NODE - 1 ; i++) {
137125329Sfsmp		if (bktr->clip_list[i].y_min == 0 &&
137225329Sfsmp		    bktr->clip_list[i].y_max == 0) {
137325329Sfsmp		    break;
137425329Sfsmp		}
137525329Sfsmp		if ( bktr->clip_list[i+1].y_min != 0 &&
137625329Sfsmp		     bktr->clip_list[i+1].y_max != 0 &&
137725329Sfsmp		     bktr->clip_list[i].x_min > bktr->clip_list[i+1].x_min ) {
137825329Sfsmp
137925329Sfsmp		    bktr->max_clip_node = 0;
138025329Sfsmp		    return (EINVAL);
138125329Sfsmp
138225329Sfsmp		 }
138325329Sfsmp
138425329Sfsmp		if (bktr->clip_list[i].x_min >= bktr->clip_list[i].x_max ||
138525329Sfsmp		    bktr->clip_list[i].y_min >= bktr->clip_list[i].y_max ||
138625329Sfsmp		    bktr->clip_list[i].x_min < 0 ||
138725329Sfsmp		    bktr->clip_list[i].x_max < 0 ||
138825329Sfsmp		    bktr->clip_list[i].y_min < 0 ||
138925329Sfsmp		    bktr->clip_list[i].y_max < 0 ) {
139025329Sfsmp		    bktr->max_clip_node = 0;
139125329Sfsmp		    return (EINVAL);
139225329Sfsmp		}
139325329Sfsmp	    }
139425329Sfsmp
139525329Sfsmp	    bktr->dma_prog_loaded = FALSE;
139625329Sfsmp
139725329Sfsmp	    break;
139825329Sfsmp
139924246Sfsmp	case METEORSTATUS:	/* get Bt848 status */
140059014Sroger		c_temp = INB(bktr, BKTR_DSTATUS);
140123599Smarkm		temp = 0;
140223599Smarkm		if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK;
140323599Smarkm		if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT;
140423599Smarkm		*(u_short *)arg = temp;
140523599Smarkm		break;
140623599Smarkm
140735259Sahasty	case BT848SFMT:		/* set input format */
140830193Smarkm		temp = *(unsigned long*)arg & BT848_IFORM_FORMAT;
140959014Sroger		temp_iform = INB(bktr, BKTR_IFORM);
141035259Sahasty		temp_iform &= ~BT848_IFORM_FORMAT;
141135259Sahasty		temp_iform &= ~BT848_IFORM_XTSEL;
141259014Sroger		OUTB(bktr, BKTR_IFORM, (temp_iform | temp | format_params[temp].iform_xtsel));
141330193Smarkm		switch( temp ) {
141430193Smarkm		case BT848_IFORM_F_AUTO:
141530193Smarkm			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
141630193Smarkm			METEOR_AUTOMODE;
141730193Smarkm			break;
141830193Smarkm
141930193Smarkm		case BT848_IFORM_F_NTSCM:
142030193Smarkm		case BT848_IFORM_F_NTSCJ:
142130193Smarkm			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
142230856Seivind				METEOR_NTSC;
142359277Sroger			OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
142459014Sroger			OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
142530856Seivind			bktr->format_params = temp;
142630193Smarkm			break;
142730193Smarkm
142830193Smarkm		case BT848_IFORM_F_PALBDGHI:
142930193Smarkm		case BT848_IFORM_F_PALN:
143030193Smarkm		case BT848_IFORM_F_SECAM:
143130193Smarkm		case BT848_IFORM_F_RSVD:
143230856Seivind		case BT848_IFORM_F_PALM:
143330193Smarkm			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
143430193Smarkm				METEOR_PAL;
143559277Sroger			OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
143659014Sroger			OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
143730856Seivind			bktr->format_params = temp;
143830856Seivind			break;
143930856Seivind
144030193Smarkm		}
144133025Sahasty		bktr->dma_prog_loaded = FALSE;
144230193Smarkm		break;
144330193Smarkm
144423599Smarkm	case METEORSFMT:	/* set input format */
144559014Sroger		temp_iform = INB(bktr, BKTR_IFORM);
144635259Sahasty		temp_iform &= ~BT848_IFORM_FORMAT;
144735259Sahasty		temp_iform &= ~BT848_IFORM_XTSEL;
144823599Smarkm		switch(*(unsigned long *)arg & METEOR_FORM_MASK ) {
144923599Smarkm		case 0:		/* default */
145023599Smarkm		case METEOR_FMT_NTSC:
145123599Smarkm			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
145223599Smarkm				METEOR_NTSC;
145359014Sroger			OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_NTSCM |
145459014Sroger		                         format_params[BT848_IFORM_F_NTSCM].iform_xtsel);
145559277Sroger			OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_NTSCM].adelay);
145659014Sroger			OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_NTSCM].bdelay);
145730856Seivind			bktr->format_params = BT848_IFORM_F_NTSCM;
145823599Smarkm			break;
145923599Smarkm
146024528Sfsmp		case METEOR_FMT_PAL:
146124528Sfsmp			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
146224528Sfsmp				METEOR_PAL;
146359014Sroger			OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_PALBDGHI |
146459014Sroger		                         format_params[BT848_IFORM_F_PALBDGHI].iform_xtsel);
146559277Sroger			OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_PALBDGHI].adelay);
146659014Sroger			OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_PALBDGHI].bdelay);
146730856Seivind			bktr->format_params = BT848_IFORM_F_PALBDGHI;
146824528Sfsmp			break;
146924528Sfsmp
147023599Smarkm		case METEOR_FMT_AUTOMODE:
147123599Smarkm			bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
147223599Smarkm				METEOR_AUTOMODE;
147359014Sroger			OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_AUTO |
147459014Sroger		                         format_params[BT848_IFORM_F_AUTO].iform_xtsel);
147523599Smarkm			break;
147623599Smarkm
147723599Smarkm		default:
147824528Sfsmp			return( EINVAL );
147923599Smarkm		}
148033025Sahasty		bktr->dma_prog_loaded = FALSE;
148123599Smarkm		break;
148223599Smarkm
148323599Smarkm	case METEORGFMT:	/* get input format */
148423599Smarkm		*(u_long *)arg = bktr->flags & METEOR_FORM_MASK;
148523599Smarkm		break;
148623599Smarkm
148730193Smarkm
148830193Smarkm	case BT848GFMT:		/* get input format */
148959014Sroger	        *(u_long *)arg = INB(bktr, BKTR_IFORM) & BT848_IFORM_FORMAT;
149030193Smarkm		break;
149130193Smarkm
149223599Smarkm	case METEORSCOUNT:	/* (re)set error counts */
149350693Sroger		counts = (struct meteor_counts *) arg;
149450693Sroger		bktr->fifo_errors = counts->fifo_errors;
149550693Sroger		bktr->dma_errors = counts->dma_errors;
149650693Sroger		bktr->frames_captured = counts->frames_captured;
149750693Sroger		bktr->even_fields_captured = counts->even_fields_captured;
149850693Sroger		bktr->odd_fields_captured = counts->odd_fields_captured;
149923599Smarkm		break;
150023599Smarkm
150123599Smarkm	case METEORGCOUNT:	/* get error counts */
150250693Sroger		counts = (struct meteor_counts *) arg;
150350693Sroger		counts->fifo_errors = bktr->fifo_errors;
150450693Sroger		counts->dma_errors = bktr->dma_errors;
150550693Sroger		counts->frames_captured = bktr->frames_captured;
150650693Sroger		counts->even_fields_captured = bktr->even_fields_captured;
150750693Sroger		counts->odd_fields_captured = bktr->odd_fields_captured;
150823599Smarkm		break;
150923599Smarkm
151023599Smarkm	case METEORGVIDEO:
151123599Smarkm		video = (struct meteor_video *)arg;
151223599Smarkm		video->addr = bktr->video.addr;
151323599Smarkm		video->width = bktr->video.width;
151423599Smarkm		video->banksize = bktr->video.banksize;
151523599Smarkm		video->ramsize = bktr->video.ramsize;
151623599Smarkm		break;
151723599Smarkm
151823599Smarkm	case METEORSVIDEO:
151923599Smarkm		video = (struct meteor_video *)arg;
152023599Smarkm		bktr->video.addr = video->addr;
152123599Smarkm		bktr->video.width = video->width;
152223599Smarkm		bktr->video.banksize = video->banksize;
152323599Smarkm		bktr->video.ramsize = video->ramsize;
152423599Smarkm		break;
152523599Smarkm
152623599Smarkm	case METEORSFPS:
152723599Smarkm		set_fps(bktr, *(u_short *)arg);
152823599Smarkm		break;
152923599Smarkm
153023599Smarkm	case METEORGFPS:
153123599Smarkm		*(u_short *)arg = bktr->fps;
153223599Smarkm		break;
153323599Smarkm
153423599Smarkm	case METEORSHUE:	/* set hue */
153559014Sroger		OUTB(bktr, BKTR_HUE, (*(u_char *) arg) & 0xff);
153623599Smarkm		break;
153723599Smarkm
153823599Smarkm	case METEORGHUE:	/* get hue */
153959014Sroger		*(u_char *)arg = INB(bktr, BKTR_HUE);
154023599Smarkm		break;
154123599Smarkm
154223599Smarkm	case METEORSBRIG:	/* set brightness */
154336090Sahasty	        char_temp =    ( *(u_char *)arg & 0xff) - 128;
154459014Sroger		OUTB(bktr, BKTR_BRIGHT, char_temp);
154536090Sahasty
154623599Smarkm		break;
154723599Smarkm
154823599Smarkm	case METEORGBRIG:	/* get brightness */
154959014Sroger		*(u_char *)arg = INB(bktr, BKTR_BRIGHT);
155023599Smarkm		break;
155123599Smarkm
155223599Smarkm	case METEORSCSAT:	/* set chroma saturation */
155323599Smarkm		temp = (int)*(u_char *)arg;
155423599Smarkm
155559014Sroger		OUTB(bktr, BKTR_SAT_U_LO, (temp << 1) & 0xff);
155659014Sroger		OUTB(bktr, BKTR_SAT_V_LO, (temp << 1) & 0xff);
155759014Sroger		OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
155859014Sroger		                     & ~(BT848_E_CONTROL_SAT_U_MSB
155959014Sroger					 | BT848_E_CONTROL_SAT_V_MSB));
156059014Sroger		OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
156159014Sroger		                     & ~(BT848_O_CONTROL_SAT_U_MSB |
156259014Sroger					 BT848_O_CONTROL_SAT_V_MSB));
156323599Smarkm
156424528Sfsmp		if ( temp & BIT_SEVEN_HIGH ) {
156559014Sroger		        OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
156659014Sroger			                     | (BT848_E_CONTROL_SAT_U_MSB
156759014Sroger						| BT848_E_CONTROL_SAT_V_MSB));
156859014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
156959014Sroger			                     | (BT848_O_CONTROL_SAT_U_MSB
157059014Sroger						| BT848_O_CONTROL_SAT_V_MSB));
157123599Smarkm		}
157223599Smarkm		break;
157323599Smarkm
157423599Smarkm	case METEORGCSAT:	/* get chroma saturation */
157559014Sroger		temp = (INB(bktr, BKTR_SAT_V_LO) >> 1) & 0xff;
157659014Sroger		if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
157724528Sfsmp			temp |= BIT_SEVEN_HIGH;
157823599Smarkm		*(u_char *)arg = (u_char)temp;
157923599Smarkm		break;
158023599Smarkm
158123599Smarkm	case METEORSCONT:	/* set contrast */
158223599Smarkm		temp = (int)*(u_char *)arg & 0xff;
158323599Smarkm		temp <<= 1;
158459014Sroger		OUTB(bktr, BKTR_CONTRAST_LO, temp & 0xff);
158559014Sroger		OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_CON_MSB);
158659014Sroger		OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_CON_MSB);
158759014Sroger		OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) |
158859014Sroger			(((temp & 0x100) >> 6 ) & BT848_E_CONTROL_CON_MSB));
158959014Sroger		OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) |
159059014Sroger			(((temp & 0x100) >> 6 ) & BT848_O_CONTROL_CON_MSB));
159123599Smarkm		break;
159223599Smarkm
159323599Smarkm	case METEORGCONT:	/* get contrast */
159459014Sroger		temp = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
159559014Sroger		temp |= ((int)INB(bktr, BKTR_O_CONTROL) & 0x04) << 6;
159623599Smarkm		*(u_char *)arg = (u_char)((temp >> 1) & 0xff);
159723599Smarkm		break;
159823599Smarkm
159936090Sahasty	case BT848SCBUF:	/* set Clear-Buffer-on-start flag */
160059014Sroger		bktr->clr_on_start = (*(int *)arg != 0);
160159014Sroger		break;
160236090Sahasty
160336090Sahasty	case BT848GCBUF:	/* get Clear-Buffer-on-start flag */
160436090Sahasty		*(int *)arg = (int) bktr->clr_on_start;
160536090Sahasty		break;
160636090Sahasty
160723599Smarkm	case METEORSSIGNAL:
1608119493Snectar		sig = *(int *)arg;
1609119493Snectar		/* Historically, applications used METEOR_SIG_MODE_MASK
1610119493Snectar		 * to reset signal delivery.
1611119493Snectar		 */
1612119493Snectar		if (sig == METEOR_SIG_MODE_MASK)
1613119493Snectar			sig = 0;
1614119493Snectar		if (sig < 0 || sig > _SIG_MAXSIG)
1615119493Snectar			return (EINVAL);
1616119493Snectar		bktr->signal = sig;
1617119493Snectar		bktr->proc = sig ? td->td_proc : NULL;
161823599Smarkm		break;
161923599Smarkm
162023599Smarkm	case METEORGSIGNAL:
162123599Smarkm		*(int *)arg = bktr->signal;
162223599Smarkm		break;
162323599Smarkm
162423599Smarkm	case METEORCAPTUR:
162523599Smarkm		temp = bktr->flags;
162623599Smarkm		switch (*(int *) arg) {
162723599Smarkm		case METEOR_CAP_SINGLE:
162823599Smarkm
162923599Smarkm			if (bktr->bigbuf==0)	/* no frame buffer allocated */
163024528Sfsmp				return( ENOMEM );
163124528Sfsmp			/* already capturing */
163224528Sfsmp			if (temp & METEOR_CAP_MASK)
163324528Sfsmp				return( EIO );
163423599Smarkm
163529233Smarkm
163629233Smarkm
163723599Smarkm			start_capture(bktr, METEOR_SINGLE);
163823599Smarkm
163923599Smarkm			/* wait for capture to complete */
164059014Sroger			OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
164159014Sroger			OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
164259014Sroger			OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
164323599Smarkm
164459014Sroger			OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
164559014Sroger			     		    BT848_INT_RISCI      |
164659014Sroger					    BT848_INT_VSYNC      |
164759014Sroger					    BT848_INT_FMTCHG);
164823599Smarkm
164959014Sroger			OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
165046176Sroger			error = tsleep(BKTR_SLEEP, BKTRPRI, "captur", hz);
165125329Sfsmp			if (error && (error != ERESTART)) {
165225329Sfsmp				/*  Here if we didn't get complete frame  */
165329233Smarkm#ifdef DIAGNOSTIC
165462112Sroger				printf( "%s: ioctl: tsleep error %d %x\n",
165562112Sroger					bktr_name(bktr), error,
165662112Sroger					INL(bktr, BKTR_RISC_COUNT));
165729233Smarkm#endif
165825329Sfsmp
165925329Sfsmp				/* stop dma */
166059014Sroger				OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
166125329Sfsmp
166225329Sfsmp				/* disable risc, leave fifo running */
166359014Sroger				OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
166423599Smarkm			}
166524528Sfsmp
166623599Smarkm			bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
166724528Sfsmp			/* FIXME: should we set bt848->int_stat ??? */
166823599Smarkm			break;
166923599Smarkm
167023599Smarkm		case METEOR_CAP_CONTINOUS:
167123599Smarkm			if (bktr->bigbuf==0)	/* no frame buffer allocated */
167224528Sfsmp				return( ENOMEM );
167329233Smarkm			/* already capturing */
167423599Smarkm			if (temp & METEOR_CAP_MASK)
167529233Smarkm			    return( EIO );
167623599Smarkm
167729233Smarkm
167823599Smarkm			start_capture(bktr, METEOR_CONTIN);
167923599Smarkm
168059014Sroger			/* Clear the interrypt status register */
168159014Sroger			OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
168223599Smarkm
168359014Sroger			OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
168459014Sroger			OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
168559014Sroger			OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
168659014Sroger
168759014Sroger			OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
168859014Sroger					    BT848_INT_RISCI      |
168959014Sroger			                    BT848_INT_VSYNC      |
169059014Sroger					    BT848_INT_FMTCHG);
169129233Smarkm#ifdef BT848_DUMP
169224087Sfsmp			dump_bt848( bt848 );
169329233Smarkm#endif
169423599Smarkm			break;
169523599Smarkm
169623599Smarkm		case METEOR_CAP_STOP_CONT:
169723599Smarkm			if (bktr->flags & METEOR_CONTIN) {
169823599Smarkm				/* turn off capture */
169959014Sroger				OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
170059014Sroger				OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
170159014Sroger				OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
170224246Sfsmp				bktr->flags &=
170324528Sfsmp					~(METEOR_CONTIN | METEOR_WANT_MASK);
170429233Smarkm
170523599Smarkm			}
170623599Smarkm		}
170723599Smarkm		break;
170823599Smarkm
170923599Smarkm	case METEORSETGEO:
171029233Smarkm		/* can't change parameters while capturing */
171129233Smarkm		if (bktr->flags & METEOR_CAP_MASK)
171229233Smarkm			return( EBUSY );
171329233Smarkm
171429233Smarkm
171523599Smarkm		geo = (struct meteor_geomet *) arg;
171623599Smarkm
171723599Smarkm		error = 0;
171823599Smarkm		/* Either even or odd, if even & odd, then these a zero */
171923599Smarkm		if ((geo->oformat & METEOR_GEO_ODD_ONLY) &&
172023599Smarkm			(geo->oformat & METEOR_GEO_EVEN_ONLY)) {
172162112Sroger			printf( "%s: ioctl: Geometry odd or even only.\n",
172262112Sroger				bktr_name(bktr));
172324528Sfsmp			return( EINVAL );
172423599Smarkm		}
172523599Smarkm
172623599Smarkm		/* set/clear even/odd flags */
172723599Smarkm		if (geo->oformat & METEOR_GEO_ODD_ONLY)
172823599Smarkm			bktr->flags |= METEOR_ONLY_ODD_FIELDS;
172923599Smarkm		else
173023599Smarkm			bktr->flags &= ~METEOR_ONLY_ODD_FIELDS;
173123599Smarkm		if (geo->oformat & METEOR_GEO_EVEN_ONLY)
173223599Smarkm			bktr->flags |= METEOR_ONLY_EVEN_FIELDS;
173323599Smarkm		else
173423599Smarkm			bktr->flags &= ~METEOR_ONLY_EVEN_FIELDS;
173523599Smarkm
173646164Sroger		if (geo->columns <= 0) {
173723599Smarkm			printf(
173862112Sroger			"%s: ioctl: %d: columns must be greater than zero.\n",
173962112Sroger				bktr_name(bktr), geo->columns);
174046164Sroger			error = EINVAL;
174146164Sroger		}
174246164Sroger		else if ((geo->columns & 0x3fe) != geo->columns) {
174346164Sroger			printf(
174462112Sroger			"%s: ioctl: %d: columns too large or not even.\n",
174562112Sroger				bktr_name(bktr), geo->columns);
174623599Smarkm			error = EINVAL;
174723599Smarkm		}
174846176Sroger
174946164Sroger		if (geo->rows <= 0) {
175046164Sroger			printf(
175162112Sroger			"%s: ioctl: %d: rows must be greater than zero.\n",
175262112Sroger				bktr_name(bktr), geo->rows);
175346164Sroger			error = EINVAL;
175446164Sroger		}
175546164Sroger		else if (((geo->rows & 0x7fe) != geo->rows) ||
175623599Smarkm			((geo->oformat & METEOR_GEO_FIELD_MASK) &&
175723599Smarkm				((geo->rows & 0x3fe) != geo->rows)) ) {
175823599Smarkm			printf(
175962112Sroger			"%s: ioctl: %d: rows too large or not even.\n",
176062112Sroger				bktr_name(bktr), geo->rows);
176123599Smarkm			error = EINVAL;
176223599Smarkm		}
176346176Sroger
176423599Smarkm		if (geo->frames > 32) {
176562112Sroger			printf("%s: ioctl: too many frames.\n",
176662112Sroger			       bktr_name(bktr));
176723599Smarkm
176823599Smarkm			error = EINVAL;
176923599Smarkm		}
177023599Smarkm
177124246Sfsmp		if (error)
177224528Sfsmp			return( error );
177323599Smarkm
177424528Sfsmp		bktr->dma_prog_loaded = FALSE;
177559014Sroger		OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
177623599Smarkm
177759014Sroger		OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
177824528Sfsmp
177929233Smarkm		if ((temp=(geo->rows * geo->columns * geo->frames * 2))) {
178023599Smarkm			if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
178123599Smarkm
178223599Smarkm			/* meteor_mem structure for SYNC Capture */
178323599Smarkm			if (geo->frames > 1) temp += PAGE_SIZE;
178423599Smarkm
178523599Smarkm			temp = btoc(temp);
178623599Smarkm			if ((int) temp > bktr->alloc_pages
178723599Smarkm			    && bktr->video.addr == 0) {
178848781Sroger
178948781Sroger/*****************************/
179048781Sroger/* *** OS Dependant code *** */
179148781Sroger/*****************************/
179248781Sroger#if defined(__NetBSD__) || defined(__OpenBSD__)
179348781Sroger                                bus_dmamap_t dmamap;
179448781Sroger
179548781Sroger                                buf = get_bktr_mem(bktr, &dmamap,
179648781Sroger                                                   temp * PAGE_SIZE);
179748781Sroger                                if (buf != 0) {
179848781Sroger                                        free_bktr_mem(bktr, bktr->dm_mem,
179948781Sroger                                                      bktr->bigbuf);
180048781Sroger                                        bktr->dm_mem = dmamap;
180148781Sroger
180248781Sroger#else
180348781Sroger                                buf = get_bktr_mem(unit, temp*PAGE_SIZE);
180448781Sroger                                if (buf != 0) {
1805254025Sjeff					contigfree(
1806254025Sjeff					  (void *)(uintptr_t)bktr->bigbuf,
1807254025Sjeff                                          (bktr->alloc_pages * PAGE_SIZE),
1808254025Sjeff					  M_DEVBUF);
180948781Sroger#endif
181048781Sroger
181123599Smarkm					bktr->bigbuf = buf;
181223599Smarkm					bktr->alloc_pages = temp;
181323599Smarkm					if (bootverbose)
1814210010Snwhitehorn						printf("%s: ioctl: Allocating %d bytes\n",
1815210010Snwhitehorn							bktr_name(bktr), (int)(temp*PAGE_SIZE));
181624528Sfsmp				}
181724528Sfsmp				else
181823599Smarkm					error = ENOMEM;
181923599Smarkm			}
182023599Smarkm		}
182123599Smarkm
182223599Smarkm		if (error)
182323599Smarkm			return error;
182423599Smarkm
182523599Smarkm		bktr->rows = geo->rows;
182623599Smarkm		bktr->cols = geo->columns;
182723599Smarkm		bktr->frames = geo->frames;
182823599Smarkm
182925329Sfsmp		/*  Pixel format (if in meteor pixfmt compatibility mode)  */
183025329Sfsmp		if ( bktr->pixfmt_compat ) {
183123599Smarkm			bktr->format = METEOR_GEO_YUV_422;
183225329Sfsmp			switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
183325329Sfsmp			case 0:			/* default */
183425329Sfsmp			case METEOR_GEO_RGB16:
183525329Sfsmp				    bktr->format = METEOR_GEO_RGB16;
183625329Sfsmp				    break;
183725329Sfsmp			case METEOR_GEO_RGB24:
183825329Sfsmp				    bktr->format = METEOR_GEO_RGB24;
183925329Sfsmp				    break;
184025329Sfsmp			case METEOR_GEO_YUV_422:
184125329Sfsmp				    bktr->format = METEOR_GEO_YUV_422;
184231186Sahasty                                    if (geo->oformat & METEOR_GEO_YUV_12)
184331186Sahasty					bktr->format = METEOR_GEO_YUV_12;
184425329Sfsmp				    break;
184525329Sfsmp			case METEOR_GEO_YUV_PACKED:
184625329Sfsmp				    bktr->format = METEOR_GEO_YUV_PACKED;
184725329Sfsmp				    break;
184825329Sfsmp			}
184925329Sfsmp			bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
185023599Smarkm		}
185123599Smarkm
185223599Smarkm		if (bktr->flags & METEOR_CAP_MASK) {
185323599Smarkm
185423599Smarkm			if (bktr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) {
185523599Smarkm				switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
185623599Smarkm				case METEOR_ONLY_ODD_FIELDS:
185723599Smarkm					bktr->flags |= METEOR_WANT_ODD;
185823599Smarkm					break;
185923599Smarkm				case METEOR_ONLY_EVEN_FIELDS:
186023599Smarkm					bktr->flags |= METEOR_WANT_EVEN;
186123599Smarkm					break;
186223599Smarkm				default:
186323599Smarkm					bktr->flags |= METEOR_WANT_MASK;
186423599Smarkm					break;
186523599Smarkm				}
186623599Smarkm
186723599Smarkm				start_capture(bktr, METEOR_CONTIN);
186859014Sroger				OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
186959014Sroger				OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
187059014Sroger				OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
187159014Sroger				OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
187259014Sroger						    BT848_INT_VSYNC      |
187359014Sroger						    BT848_INT_FMTCHG);
187423599Smarkm			}
187523599Smarkm		}
187623599Smarkm		break;
187724046Sfsmp	/* end of METEORSETGEO */
187824046Sfsmp
187938707Ssos	/* FIXME. The Capture Area currently has the following restrictions:
188038706Ssos	GENERAL
188138706Ssos	 y_offset may need to be even in interlaced modes
188238706Ssos	RGB24 - Interlaced mode
188338706Ssos	 x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
188438706Ssos	 y_size must be greater than or equal to METEORSETGEO height (rows)
188538706Ssos	RGB24 - Even Only (or Odd Only) mode
188638706Ssos	 x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
188738706Ssos	 y_size must be greater than or equal to 2*METEORSETGEO height (rows)
188838706Ssos	YUV12 - Interlaced mode
188938706Ssos	 x_size must be greater than or equal to METEORSETGEO width (cols)
189038706Ssos	 y_size must be greater than or equal to METEORSETGEO height (rows)
189138706Ssos	YUV12 - Even Only (or Odd Only) mode
189238706Ssos	 x_size must be greater than or equal to METEORSETGEO width (cols)
189338706Ssos	 y_size must be greater than or equal to 2*METEORSETGEO height (rows)
189438706Ssos	*/
189538706Ssos
189638707Ssos	case BT848_SCAPAREA: /* set capture area of each video frame */
189738706Ssos		/* can't change parameters while capturing */
189838706Ssos		if (bktr->flags & METEOR_CAP_MASK)
189938706Ssos			return( EBUSY );
190038706Ssos
190138706Ssos		cap_area = (struct bktr_capture_area *) arg;
190238706Ssos		bktr->capture_area_x_offset = cap_area->x_offset;
190338706Ssos		bktr->capture_area_y_offset = cap_area->y_offset;
190438706Ssos		bktr->capture_area_x_size   = cap_area->x_size;
190538706Ssos		bktr->capture_area_y_size   = cap_area->y_size;
190638706Ssos		bktr->capture_area_enabled  = TRUE;
190738706Ssos
190838706Ssos		bktr->dma_prog_loaded = FALSE;
190938706Ssos		break;
191038706Ssos
191138707Ssos	case BT848_GCAPAREA: /* get capture area of each video frame */
191238706Ssos		cap_area = (struct bktr_capture_area *) arg;
191338706Ssos		if (bktr->capture_area_enabled == FALSE) {
191438706Ssos			cap_area->x_offset = 0;
191538706Ssos			cap_area->y_offset = 0;
191638706Ssos			cap_area->x_size   = format_params[
191738706Ssos				bktr->format_params].scaled_hactive;
191838706Ssos			cap_area->y_size   = format_params[
191938706Ssos				bktr->format_params].vactive;
192038706Ssos		} else {
192138706Ssos			cap_area->x_offset = bktr->capture_area_x_offset;
192238706Ssos			cap_area->y_offset = bktr->capture_area_y_offset;
192338706Ssos			cap_area->x_size   = bktr->capture_area_x_size;
192438706Ssos			cap_area->y_size   = bktr->capture_area_y_size;
192538706Ssos		}
192638706Ssos		break;
192738706Ssos
192824046Sfsmp	default:
192959014Sroger		return common_ioctl( bktr, cmd, arg );
193023599Smarkm	}
193123599Smarkm
193224528Sfsmp	return( 0 );
193323599Smarkm}
193423599Smarkm
193523599Smarkm/*
193624246Sfsmp * tuner ioctls
193724246Sfsmp */
193851694Srogerint
193983366Sjuliantuner_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td )
194024246Sfsmp{
194124528Sfsmp	int		tmp_int;
1942249816Sjkim	int		temp, temp1;
194324528Sfsmp	int		offset;
194424528Sfsmp	int		count;
194524528Sfsmp	u_char		*buf;
194633638Sahasty	u_long          par;
194733638Sahasty	u_char          write;
194833638Sahasty	int             i2c_addr;
194933638Sahasty	int             i2c_port;
195033638Sahasty	u_long          data;
195124246Sfsmp
195224246Sfsmp	switch ( cmd ) {
195324246Sfsmp
195443890Sroger	case REMOTE_GETKEY:
195543890Sroger		/* Read the last key pressed by the Remote Control */
195643890Sroger		if (bktr->remote_control == 0) return (EINVAL);
195743890Sroger		remote_read(bktr, (struct bktr_remote *)arg);
195843890Sroger		break;
195943890Sroger
196024528Sfsmp#if defined( TUNER_AFC )
196124528Sfsmp	case TVTUNER_SETAFC:
196224528Sfsmp		bktr->tuner.afc = (*(int *)arg != 0);
196324528Sfsmp		break;
196424528Sfsmp
196524528Sfsmp	case TVTUNER_GETAFC:
196624528Sfsmp		*(int *)arg = bktr->tuner.afc;
196724528Sfsmp		/* XXX Perhaps use another bit to indicate AFC success? */
196824528Sfsmp		break;
196924528Sfsmp#endif /* TUNER_AFC */
197024528Sfsmp
197124246Sfsmp	case TVTUNER_SETCHNL:
197224528Sfsmp		temp_mute( bktr, TRUE );
197324246Sfsmp		temp = tv_channel( bktr, (int)*(unsigned long *)arg );
197451694Sroger		if ( temp < 0 ) {
197551694Sroger			temp_mute( bktr, FALSE );
197624528Sfsmp			return( EINVAL );
197751694Sroger		}
197824246Sfsmp		*(unsigned long *)arg = temp;
197943353Sroger
198043353Sroger		/* after every channel change, we must restart the MSP34xx */
198143353Sroger		/* audio chip to reselect NICAM STEREO or MONO audio */
198243353Sroger		if ( bktr->card.msp3400c )
198343353Sroger		  msp_autodetect( bktr );
198451694Sroger
198552593Sroger		/* after every channel change, we must restart the DPL35xx */
198652593Sroger		if ( bktr->card.dpl3518a )
198752593Sroger		  dpl_autodetect( bktr );
198852593Sroger
198951694Sroger		temp_mute( bktr, FALSE );
199024246Sfsmp		break;
199124246Sfsmp
199224246Sfsmp	case TVTUNER_GETCHNL:
199324246Sfsmp		*(unsigned long *)arg = bktr->tuner.channel;
199424246Sfsmp		break;
199524246Sfsmp
199624246Sfsmp	case TVTUNER_SETTYPE:
199724246Sfsmp		temp = *(unsigned long *)arg;
199824246Sfsmp		if ( (temp < CHNLSET_MIN) || (temp > CHNLSET_MAX) )
199924528Sfsmp			return( EINVAL );
200024246Sfsmp		bktr->tuner.chnlset = temp;
200124246Sfsmp		break;
200224246Sfsmp
200324246Sfsmp	case TVTUNER_GETTYPE:
200424246Sfsmp		*(unsigned long *)arg = bktr->tuner.chnlset;
200524246Sfsmp		break;
200624246Sfsmp
200724246Sfsmp	case TVTUNER_GETSTATUS:
200851694Sroger		temp = get_tuner_status( bktr );
200924246Sfsmp		*(unsigned long *)arg = temp & 0xff;
201024246Sfsmp		break;
201124246Sfsmp
201224246Sfsmp	case TVTUNER_SETFREQ:
201324528Sfsmp		temp_mute( bktr, TRUE );
201451694Sroger		temp = tv_freq( bktr, (int)*(unsigned long *)arg, TV_FREQUENCY);
201524528Sfsmp		temp_mute( bktr, FALSE );
201651694Sroger		if ( temp < 0 ) {
201751694Sroger			temp_mute( bktr, FALSE );
201824528Sfsmp			return( EINVAL );
201951694Sroger		}
202024246Sfsmp		*(unsigned long *)arg = temp;
202143353Sroger
202243353Sroger		/* after every channel change, we must restart the MSP34xx */
202343353Sroger		/* audio chip to reselect NICAM STEREO or MONO audio */
202443353Sroger		if ( bktr->card.msp3400c )
202543353Sroger		  msp_autodetect( bktr );
202651694Sroger
202752593Sroger		/* after every channel change, we must restart the DPL35xx */
202852593Sroger		if ( bktr->card.dpl3518a )
202952593Sroger		  dpl_autodetect( bktr );
203052593Sroger
203151694Sroger		temp_mute( bktr, FALSE );
203224246Sfsmp		break;
203324246Sfsmp
203424246Sfsmp	case TVTUNER_GETFREQ:
203524246Sfsmp		*(unsigned long *)arg = bktr->tuner.frequency;
203624246Sfsmp		break;
203724246Sfsmp
203843890Sroger	case TVTUNER_GETCHNLSET:
203943890Sroger		return tuner_getchnlset((struct bktr_chnlset *)arg);
204043890Sroger
204124246Sfsmp	case BT848_SAUDIO:	/* set audio channel */
204224246Sfsmp		if ( set_audio( bktr, *(int*)arg ) < 0 )
204324528Sfsmp			return( EIO );
204424246Sfsmp		break;
204524246Sfsmp
204624246Sfsmp	/* hue is a 2's compliment number, -90' to +89.3' in 0.7' steps */
204724246Sfsmp	case BT848_SHUE:	/* set hue */
204859014Sroger		OUTB(bktr, BKTR_HUE, (u_char)(*(int*)arg & 0xff));
204924246Sfsmp		break;
205024246Sfsmp
205124246Sfsmp	case BT848_GHUE:	/* get hue */
205259014Sroger		*(int*)arg = (signed char)(INB(bktr, BKTR_HUE) & 0xff);
205324246Sfsmp		break;
205424246Sfsmp
205524246Sfsmp	/* brightness is a 2's compliment #, -50 to +%49.6% in 0.39% steps */
205624246Sfsmp	case BT848_SBRIG:	/* set brightness */
205759014Sroger		OUTB(bktr, BKTR_BRIGHT, (u_char)(*(int *)arg & 0xff));
205824246Sfsmp		break;
205924246Sfsmp
206024246Sfsmp	case BT848_GBRIG:	/* get brightness */
206159014Sroger		*(int *)arg = (signed char)(INB(bktr, BKTR_BRIGHT) & 0xff);
206224246Sfsmp		break;
206324246Sfsmp
206424246Sfsmp	/*  */
206524246Sfsmp	case BT848_SCSAT:	/* set chroma saturation */
206624246Sfsmp		tmp_int = *(int*)arg;
206724246Sfsmp
206859014Sroger		temp = INB(bktr, BKTR_E_CONTROL);
206959014Sroger		temp1 = INB(bktr, BKTR_O_CONTROL);
207024528Sfsmp		if ( tmp_int & BIT_EIGHT_HIGH ) {
207124528Sfsmp			temp |= (BT848_E_CONTROL_SAT_U_MSB |
207224528Sfsmp				 BT848_E_CONTROL_SAT_V_MSB);
207324528Sfsmp			temp1 |= (BT848_O_CONTROL_SAT_U_MSB |
207424528Sfsmp				  BT848_O_CONTROL_SAT_V_MSB);
207524246Sfsmp		}
207624528Sfsmp		else {
207724528Sfsmp			temp &= ~(BT848_E_CONTROL_SAT_U_MSB |
207824528Sfsmp				  BT848_E_CONTROL_SAT_V_MSB);
207924528Sfsmp			temp1 &= ~(BT848_O_CONTROL_SAT_U_MSB |
208024528Sfsmp				   BT848_O_CONTROL_SAT_V_MSB);
208124528Sfsmp		}
208224246Sfsmp
208359014Sroger		OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
208459014Sroger		OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
208559014Sroger		OUTB(bktr, BKTR_E_CONTROL, temp);
208659014Sroger		OUTB(bktr, BKTR_O_CONTROL, temp1);
208724246Sfsmp		break;
208824246Sfsmp
208924246Sfsmp	case BT848_GCSAT:	/* get chroma saturation */
209059014Sroger		tmp_int = (int)(INB(bktr, BKTR_SAT_V_LO) & 0xff);
209159014Sroger		if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
209224528Sfsmp			tmp_int |= BIT_EIGHT_HIGH;
209324246Sfsmp		*(int*)arg = tmp_int;
209424246Sfsmp		break;
209524246Sfsmp
209624246Sfsmp	/*  */
209724246Sfsmp	case BT848_SVSAT:	/* set chroma V saturation */
209824246Sfsmp		tmp_int = *(int*)arg;
209924246Sfsmp
210059014Sroger		temp = INB(bktr, BKTR_E_CONTROL);
210159014Sroger		temp1 = INB(bktr, BKTR_O_CONTROL);
210224528Sfsmp		if ( tmp_int & BIT_EIGHT_HIGH) {
210324528Sfsmp			temp |= BT848_E_CONTROL_SAT_V_MSB;
210424528Sfsmp			temp1 |= BT848_O_CONTROL_SAT_V_MSB;
210524246Sfsmp		}
210624528Sfsmp		else {
210724528Sfsmp			temp &= ~BT848_E_CONTROL_SAT_V_MSB;
210824528Sfsmp			temp1 &= ~BT848_O_CONTROL_SAT_V_MSB;
210924528Sfsmp		}
211024246Sfsmp
211159014Sroger		OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
211259014Sroger		OUTB(bktr, BKTR_E_CONTROL, temp);
211359014Sroger		OUTB(bktr, BKTR_O_CONTROL, temp1);
211424246Sfsmp		break;
211524246Sfsmp
211624246Sfsmp	case BT848_GVSAT:	/* get chroma V saturation */
211759014Sroger		tmp_int = (int)INB(bktr, BKTR_SAT_V_LO) & 0xff;
211859014Sroger		if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
211924528Sfsmp			tmp_int |= BIT_EIGHT_HIGH;
212024246Sfsmp		*(int*)arg = tmp_int;
212124246Sfsmp		break;
212224246Sfsmp
212324246Sfsmp	/*  */
212424246Sfsmp	case BT848_SUSAT:	/* set chroma U saturation */
212524246Sfsmp		tmp_int = *(int*)arg;
212624246Sfsmp
212759014Sroger		temp = INB(bktr, BKTR_E_CONTROL);
212859014Sroger		temp1 = INB(bktr, BKTR_O_CONTROL);
212924528Sfsmp		if ( tmp_int & BIT_EIGHT_HIGH ) {
213024528Sfsmp			temp |= BT848_E_CONTROL_SAT_U_MSB;
213124528Sfsmp			temp1 |= BT848_O_CONTROL_SAT_U_MSB;
213224246Sfsmp		}
213324528Sfsmp		else {
213424528Sfsmp			temp &= ~BT848_E_CONTROL_SAT_U_MSB;
213524528Sfsmp			temp1 &= ~BT848_O_CONTROL_SAT_U_MSB;
213624528Sfsmp		}
213724246Sfsmp
213859014Sroger		OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
213959014Sroger		OUTB(bktr, BKTR_E_CONTROL, temp);
214059014Sroger		OUTB(bktr, BKTR_O_CONTROL, temp1);
214124246Sfsmp		break;
214224246Sfsmp
214324246Sfsmp	case BT848_GUSAT:	/* get chroma U saturation */
214459014Sroger		tmp_int = (int)INB(bktr, BKTR_SAT_U_LO) & 0xff;
214559014Sroger		if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_U_MSB )
214624528Sfsmp			tmp_int |= BIT_EIGHT_HIGH;
214724246Sfsmp		*(int*)arg = tmp_int;
214824246Sfsmp		break;
214924246Sfsmp
215029233Smarkm/* lr 970528 luma notch etc - 3 high bits of e_control/o_control */
215129233Smarkm
215229233Smarkm	case BT848_SLNOTCH:	/* set luma notch */
215329233Smarkm		tmp_int = (*(int *)arg & 0x7) << 5 ;
215459014Sroger		OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~0xe0);
215559014Sroger		OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~0xe0);
215659014Sroger		OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | tmp_int);
215759014Sroger		OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | tmp_int);
215829233Smarkm		break;
215929233Smarkm
216029233Smarkm	case BT848_GLNOTCH:	/* get luma notch */
216159014Sroger		*(int *)arg = (int) ( (INB(bktr, BKTR_E_CONTROL) & 0xe0) >> 5) ;
216229233Smarkm		break;
216329233Smarkm
216429233Smarkm
216524246Sfsmp	/*  */
216624246Sfsmp	case BT848_SCONT:	/* set contrast */
216724246Sfsmp		tmp_int = *(int*)arg;
216824246Sfsmp
216959014Sroger		temp = INB(bktr, BKTR_E_CONTROL);
217059014Sroger		temp1 = INB(bktr, BKTR_O_CONTROL);
217124528Sfsmp		if ( tmp_int & BIT_EIGHT_HIGH ) {
217224528Sfsmp			temp |= BT848_E_CONTROL_CON_MSB;
217324528Sfsmp			temp1 |= BT848_O_CONTROL_CON_MSB;
217424246Sfsmp		}
217524528Sfsmp		else {
217624528Sfsmp			temp &= ~BT848_E_CONTROL_CON_MSB;
217724528Sfsmp			temp1 &= ~BT848_O_CONTROL_CON_MSB;
217824528Sfsmp		}
217924246Sfsmp
218059014Sroger		OUTB(bktr, BKTR_CONTRAST_LO, (u_char)(tmp_int & 0xff));
218159014Sroger		OUTB(bktr, BKTR_E_CONTROL, temp);
218259014Sroger		OUTB(bktr, BKTR_O_CONTROL, temp1);
218324246Sfsmp		break;
218424246Sfsmp
218524246Sfsmp	case BT848_GCONT:	/* get contrast */
218659014Sroger		tmp_int = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
218759014Sroger		if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_CON_MSB )
218824528Sfsmp			tmp_int |= BIT_EIGHT_HIGH;
218924246Sfsmp		*(int*)arg = tmp_int;
219024246Sfsmp		break;
219124246Sfsmp
219225329Sfsmp		/*  FIXME:  SCBARS and CCBARS require a valid int *        */
219325329Sfsmp		/*    argument to succeed, but its not used; consider      */
219425329Sfsmp		/*    using the arg to store the on/off state so           */
219525329Sfsmp		/*    there's only one ioctl() needed to turn cbars on/off */
219624246Sfsmp	case BT848_SCBARS:	/* set colorbar output */
219759014Sroger		OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_COLOR_BARS);
219824246Sfsmp		break;
219924246Sfsmp
220024246Sfsmp	case BT848_CCBARS:	/* clear colorbar output */
220159014Sroger		OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) & ~(BT848_COLOR_CTL_COLOR_BARS));
220224246Sfsmp		break;
220324246Sfsmp
220424246Sfsmp	case BT848_GAUDIO:	/* get audio channel */
220524246Sfsmp		temp = bktr->audio_mux_select;
220624246Sfsmp		if ( bktr->audio_mute_state == TRUE )
220724246Sfsmp			temp |= AUDIO_MUTE;
220824246Sfsmp		*(int*)arg = temp;
220924246Sfsmp		break;
221024246Sfsmp
221124246Sfsmp	case BT848_SBTSC:	/* set audio channel */
221224246Sfsmp		if ( set_BTSC( bktr, *(int*)arg ) < 0 )
221324528Sfsmp			return( EIO );
221424246Sfsmp		break;
221524246Sfsmp
221624246Sfsmp	case BT848_WEEPROM:	/* write eeprom */
221724528Sfsmp		offset = (((struct eeProm *)arg)->offset);
221824528Sfsmp		count = (((struct eeProm *)arg)->count);
221924528Sfsmp		buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
222024528Sfsmp		if ( writeEEProm( bktr, offset, count, buf ) < 0 )
222124528Sfsmp			return( EIO );
222224528Sfsmp		break;
222324246Sfsmp
222424246Sfsmp	case BT848_REEPROM:	/* read eeprom */
222524246Sfsmp		offset = (((struct eeProm *)arg)->offset);
222624246Sfsmp		count = (((struct eeProm *)arg)->count);
222724246Sfsmp		buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
222824246Sfsmp		if ( readEEProm( bktr, offset, count, buf ) < 0 )
222924528Sfsmp			return( EIO );
223024246Sfsmp		break;
223124246Sfsmp
223224528Sfsmp	case BT848_SIGNATURE:
223324528Sfsmp		offset = (((struct eeProm *)arg)->offset);
223424528Sfsmp		count = (((struct eeProm *)arg)->count);
223524528Sfsmp		buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
223624528Sfsmp		if ( signCard( bktr, offset, count, buf ) < 0 )
223724528Sfsmp			return( EIO );
223824528Sfsmp		break;
223943890Sroger
224043890Sroger        /* Ioctl's for direct gpio access */
224143890Sroger#ifdef BKTR_GPIO_ACCESS
224243890Sroger        case BT848_GPIO_GET_EN:
224359014Sroger                *(int*)arg = INL(bktr, BKTR_GPIO_OUT_EN);
224443890Sroger                break;
224543890Sroger
224643890Sroger        case BT848_GPIO_SET_EN:
224759014Sroger                OUTL(bktr, BKTR_GPIO_OUT_EN, *(int*)arg);
224843890Sroger                break;
224943890Sroger
225043890Sroger        case BT848_GPIO_GET_DATA:
225159014Sroger                *(int*)arg = INL(bktr, BKTR_GPIO_DATA);
225243890Sroger                break;
225343890Sroger
225443890Sroger        case BT848_GPIO_SET_DATA:
225559014Sroger                OUTL(bktr, BKTR_GPIO_DATA, *(int*)arg);
225643890Sroger                break;
225743890Sroger#endif /* BKTR_GPIO_ACCESS */
225843890Sroger
225933025Sahasty	/* Ioctl's for running the tuner device in radio mode		*/
226033850Sahasty
226133850Sahasty	case RADIO_GETMODE:
226233850Sahasty            *(unsigned char *)arg = bktr->tuner.radio_mode;
226333025Sahasty	    break;
226433850Sahasty
226533850Sahasty	case RADIO_SETMODE:
226633850Sahasty            bktr->tuner.radio_mode = *(unsigned char *)arg;
226733850Sahasty            break;
226833850Sahasty
226933850Sahasty 	case RADIO_GETFREQ:
227051694Sroger            *(unsigned long *)arg = bktr->tuner.frequency;
227133850Sahasty            break;
227233850Sahasty
227333025Sahasty	case RADIO_SETFREQ:
227433025Sahasty	    /* The argument to this ioctl is NOT freq*16. It is
227533025Sahasty	    ** freq*100.
227633025Sahasty	    */
227724528Sfsmp
227851694Sroger            temp=(int)*(unsigned long *)arg;
227933025Sahasty
228033025Sahasty#ifdef BKTR_RADIO_DEBUG
228162112Sroger	    printf("%s: arg=%d temp=%d\n", bktr_name(bktr),
228262112Sroger		   (int)*(unsigned long *)arg, temp);
228333025Sahasty#endif
228433025Sahasty
228533025Sahasty#ifndef BKTR_RADIO_NOFREQCHECK
228633025Sahasty	    /* According to the spec. sheet the band: 87.5MHz-108MHz	*/
228733025Sahasty	    /* is supported.						*/
228851694Sroger	    if(temp<8750 || temp>10800) {
228962112Sroger	      printf("%s: Radio frequency out of range\n", bktr_name(bktr));
229033025Sahasty	      return(EINVAL);
229133025Sahasty	      }
229233025Sahasty#endif
229333025Sahasty	    temp_mute( bktr, TRUE );
229451694Sroger	    temp = tv_freq( bktr, temp, FM_RADIO_FREQUENCY );
229533025Sahasty	    temp_mute( bktr, FALSE );
229633025Sahasty#ifdef BKTR_RADIO_DEBUG
229733025Sahasty  if(temp)
229862112Sroger    printf("%s: tv_freq returned: %d\n", bktr_name(bktr), temp);
229933025Sahasty#endif
230033025Sahasty	    if ( temp < 0 )
230133025Sahasty		    return( EINVAL );
230233025Sahasty	    *(unsigned long *)arg = temp;
230333025Sahasty	    break;
230451694Sroger
230551694Sroger	/* Luigi's I2CWR ioctl */
230633638Sahasty	case BT848_I2CWR:
230733638Sahasty		par = *(u_long *)arg;
230833638Sahasty		write = (par >> 24) & 0xff ;
230933638Sahasty		i2c_addr = (par >> 16) & 0xff ;
231033638Sahasty		i2c_port = (par >> 8) & 0xff ;
231133638Sahasty		data = (par) & 0xff ;
231233025Sahasty
231333638Sahasty		if (write) {
231433638Sahasty			i2cWrite( bktr, i2c_addr, i2c_port, data);
231533638Sahasty		} else {
231633638Sahasty			data = i2cRead( bktr, i2c_addr);
231733638Sahasty		}
231833638Sahasty		*(u_long *)arg = (par & 0xffffff00) | ( data & 0xff );
231933638Sahasty		break;
232033025Sahasty
232133638Sahasty
232268071Sroger#ifdef BT848_MSP_READ
232368071Sroger	/* I2C ioctls to allow userland access to the MSP chip */
232468071Sroger	case BT848_MSP_READ:
232568071Sroger		{
232668071Sroger		struct bktr_msp_control *msp;
232768071Sroger		msp = (struct bktr_msp_control *) arg;
232868071Sroger		msp->data = msp_dpl_read(bktr, bktr->msp_addr,
232968071Sroger		                         msp->function, msp->address);
233068071Sroger		break;
233168071Sroger		}
233268071Sroger
233368071Sroger	case BT848_MSP_WRITE:
233468071Sroger		{
233568071Sroger		struct bktr_msp_control *msp;
233668071Sroger		msp = (struct bktr_msp_control *) arg;
233768071Sroger		msp_dpl_write(bktr, bktr->msp_addr, msp->function,
233868071Sroger		             msp->address, msp->data );
233968071Sroger		break;
234068071Sroger		}
234168071Sroger
234268071Sroger	case BT848_MSP_RESET:
234368071Sroger		msp_dpl_reset(bktr, bktr->msp_addr);
234468071Sroger		break;
234568071Sroger#endif
234668071Sroger
234724246Sfsmp	default:
234859014Sroger		return common_ioctl( bktr, cmd, arg );
234924246Sfsmp	}
235024246Sfsmp
235124246Sfsmp	return( 0 );
235224246Sfsmp}
235324246Sfsmp
235424246Sfsmp
235524246Sfsmp/*
235624246Sfsmp * common ioctls
235724246Sfsmp */
2358104094Sphkstatic int
235959014Srogercommon_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg )
236024246Sfsmp{
236129233Smarkm        int                           pixfmt;
236229233Smarkm	unsigned int	              temp;
236325329Sfsmp	struct meteor_pixfmt          *pf_pub;
236424246Sfsmp
236524246Sfsmp	switch (cmd) {
236624246Sfsmp
236724246Sfsmp	case METEORSINPUT:	/* set input device */
236847491Sroger		/*Bt848 has 3 MUX Inputs. Bt848A/849A/878/879 has 4 MUX Inputs*/
236939041Ssos		/* On the original bt848 boards, */
237039041Ssos		/*   Tuner is MUX0, RCA is MUX1, S-Video is MUX2 */
237139041Ssos		/* On the Hauppauge bt878 boards, */
237244252Sroger		/*   Tuner is MUX0, RCA is MUX3 */
237339041Ssos		/* Unfortunatly Meteor driver codes DEV_RCA as DEV_0, so we */
237439041Ssos		/* stick with this system in our Meteor Emulation */
237539041Ssos
237624246Sfsmp		switch(*(unsigned long *)arg & METEOR_DEV_MASK) {
237724246Sfsmp
237824246Sfsmp		/* this is the RCA video input */
237924246Sfsmp		case 0:		/* default */
238024246Sfsmp		case METEOR_INPUT_DEV0:
238139041Ssos		  /* METEOR_INPUT_DEV_RCA: */
238237631Sahasty		        bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
238337631Sahasty			  | METEOR_DEV0;
238459014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM)
238559014Sroger			                 & ~BT848_IFORM_MUXSEL);
238639041Ssos
238739041Ssos			/* work around for new Hauppauge 878 cards */
238839041Ssos			if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
238943770Sroger				(bktr->id==BROOKTREE_878 ||
239043770Sroger				 bktr->id==BROOKTREE_879) )
239159014Sroger				OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
239239041Ssos			else
239359014Sroger				OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
239439041Ssos
239559014Sroger			OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
239659014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
239724246Sfsmp			set_audio( bktr, AUDIO_EXTERN );
239824246Sfsmp			break;
239924246Sfsmp
240024246Sfsmp		/* this is the tuner input */
240124246Sfsmp		case METEOR_INPUT_DEV1:
240224246Sfsmp			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
240324246Sfsmp				| METEOR_DEV1;
240459014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
240559014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX0);
240659014Sroger			OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
240759014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
240824246Sfsmp			set_audio( bktr, AUDIO_TUNER );
240924246Sfsmp			break;
241024246Sfsmp
241143353Sroger		/* this is the S-VHS input, but with a composite camera */
241224246Sfsmp		case METEOR_INPUT_DEV2:
241324246Sfsmp			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
241424246Sfsmp				| METEOR_DEV2;
241559014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
241659014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
241759014Sroger			OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
241859014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_O_CONTROL_COMP);
241943353Sroger			set_audio( bktr, AUDIO_EXTERN );
242043353Sroger			break;
242143353Sroger
242243353Sroger		/* this is the S-VHS input */
242343353Sroger		case METEOR_INPUT_DEV_SVIDEO:
242443353Sroger			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
242543353Sroger				| METEOR_DEV_SVIDEO;
242659014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
242759014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
242859014Sroger			OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_COMP);
242959014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_COMP);
243024246Sfsmp			set_audio( bktr, AUDIO_EXTERN );
243124246Sfsmp			break;
243224246Sfsmp
243337611Sahasty		case METEOR_INPUT_DEV3:
243443770Sroger		  if ((bktr->id == BROOKTREE_848A) ||
243547491Sroger		      (bktr->id == BROOKTREE_849A) ||
243643770Sroger		      (bktr->id == BROOKTREE_878) ||
243743770Sroger		      (bktr->id == BROOKTREE_879) ) {
243837611Sahasty			bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
243937611Sahasty				| METEOR_DEV3;
244059014Sroger			OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
244143353Sroger
244243353Sroger			/* work around for new Hauppauge 878 cards */
244343353Sroger			if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
244443770Sroger				(bktr->id==BROOKTREE_878 ||
244543770Sroger				 bktr->id==BROOKTREE_879) )
244659014Sroger				OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
244743353Sroger			else
244859014Sroger				OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
244943353Sroger
245059014Sroger			OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
245159014Sroger			OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
245237611Sahasty			set_audio( bktr, AUDIO_EXTERN );
245337611Sahasty
245437611Sahasty			break;
245537611Sahasty		  }
245637611Sahasty
245724246Sfsmp		default:
245824528Sfsmp			return( EINVAL );
245924246Sfsmp		}
246024246Sfsmp		break;
246124246Sfsmp
246224246Sfsmp	case METEORGINPUT:	/* get input device */
246324246Sfsmp		*(u_long *)arg = bktr->flags & METEOR_DEV_MASK;
246424246Sfsmp		break;
246524246Sfsmp
246625329Sfsmp	case METEORSACTPIXFMT:
246725329Sfsmp		if (( *(int *)arg < 0 ) ||
246825329Sfsmp		    ( *(int *)arg >= PIXFMT_TABLE_SIZE ))
246925329Sfsmp			return( EINVAL );
247025329Sfsmp
247125329Sfsmp		bktr->pixfmt          = *(int *)arg;
247259014Sroger		OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
247359014Sroger		     | pixfmt_swap_flags( bktr->pixfmt ));
247425329Sfsmp		bktr->pixfmt_compat   = FALSE;
247525329Sfsmp		break;
247625329Sfsmp
247725329Sfsmp	case METEORGACTPIXFMT:
247825329Sfsmp		*(int *)arg = bktr->pixfmt;
247925329Sfsmp		break;
248025329Sfsmp
248125329Sfsmp	case METEORGSUPPIXFMT :
248225329Sfsmp		pf_pub = (struct meteor_pixfmt *)arg;
248325329Sfsmp		pixfmt = pf_pub->index;
248425329Sfsmp
248525329Sfsmp		if (( pixfmt < 0 ) || ( pixfmt >= PIXFMT_TABLE_SIZE ))
248625329Sfsmp			return( EINVAL );
248725329Sfsmp
248825329Sfsmp		memcpy( pf_pub, &pixfmt_table[ pixfmt ].public,
248925329Sfsmp			sizeof( *pf_pub ) );
249025329Sfsmp
249125329Sfsmp		/*  Patch in our format index  */
249225329Sfsmp		pf_pub->index       = pixfmt;
249325329Sfsmp		break;
249425329Sfsmp
249524528Sfsmp#if defined( STATUS_SUM )
249624246Sfsmp	case BT848_GSTATUS:	/* reap status */
249759277Sroger		{
249859277Sroger                DECLARE_INTR_MASK(s);
249959277Sroger		DISABLE_INTR(s);
250024246Sfsmp		temp = status_sum;
250124246Sfsmp		status_sum = 0;
250259250Sroger		ENABLE_INTR(s);
250324246Sfsmp		*(u_int*)arg = temp;
250424246Sfsmp		break;
250559250Sroger		}
250624528Sfsmp#endif /* STATUS_SUM */
250724246Sfsmp
250824246Sfsmp	default:
250925329Sfsmp		return( ENOTTY );
251024246Sfsmp	}
251124246Sfsmp
251224246Sfsmp	return( 0 );
251324246Sfsmp}
251424246Sfsmp
251524246Sfsmp
251623599Smarkm
251723599Smarkm
251823599Smarkm/******************************************************************************
251924087Sfsmp * bt848 RISC programming routines:
252023599Smarkm */
252123599Smarkm
252223599Smarkm
252324087Sfsmp/*
252424087Sfsmp *
252524087Sfsmp */
252629233Smarkm#ifdef BT848_DEBUG
252724087Sfsmpstatic int
252859014Srogerdump_bt848( bktr_ptr_t bktr )
252924087Sfsmp{
253024087Sfsmp	int	r[60]={
253124087Sfsmp			   4,    8, 0xc, 0x8c, 0x10, 0x90, 0x14, 0x94,
253224087Sfsmp			0x18, 0x98, 0x1c, 0x9c, 0x20, 0xa0, 0x24, 0xa4,
253324087Sfsmp			0x28, 0x2c, 0xac, 0x30, 0x34, 0x38, 0x3c, 0x40,
253424087Sfsmp			0xc0, 0x48, 0x4c, 0xcc, 0x50, 0xd0, 0xd4, 0x60,
253524087Sfsmp			0x64, 0x68, 0x6c, 0xec, 0xd8, 0xdc, 0xe0, 0xe4,
253624087Sfsmp			0,	 0,    0,    0
253724087Sfsmp		   };
253824087Sfsmp	int	i;
253924046Sfsmp
254024087Sfsmp	for (i = 0; i < 40; i+=4) {
254162112Sroger		printf("%s: Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n",
254262112Sroger		       bktr_name(bktr),
254359014Sroger		       r[i], INL(bktr, r[i]),
254459014Sroger		       r[i+1], INL(bktr, r[i+1]),
254559014Sroger		       r[i+2], INL(bktr, r[i+2]),
254659014Sroger		       r[i+3], INL(bktr, r[i+3]]));
254724087Sfsmp	}
254824046Sfsmp
254962112Sroger	printf("%s: INT STAT %x \n", bktr_name(bktr),
255062112Sroger	       INL(bktr, BKTR_INT_STAT));
255162112Sroger	printf("%s: Reg INT_MASK %x \n", bktr_name(bktr),
255262112Sroger	       INL(bktr, BKTR_INT_MASK));
255362112Sroger	printf("%s: Reg GPIO_DMA_CTL %x \n", bktr_name(bktr),
255462112Sroger	       INW(bktr, BKTR_GPIO_DMA_CTL));
255524087Sfsmp
255624528Sfsmp	return( 0 );
255724087Sfsmp}
255824087Sfsmp
255929233Smarkm#endif
256029233Smarkm
256123599Smarkm/*
256224087Sfsmp * build write instruction
256323599Smarkm */
256429233Smarkm#define BKTR_FM1      0x6	/* packed data to follow */
256529233Smarkm#define BKTR_FM3      0xe	/* planar data to follow */
256646176Sroger#define BKTR_VRE      0x4	/* Marks the end of the even field */
256746176Sroger#define BKTR_VRO      0xC	/* Marks the end of the odd field */
256829233Smarkm#define BKTR_PXV      0x0	/* valid word (never used) */
256929233Smarkm#define BKTR_EOL      0x1	/* last dword, 4 bytes */
257029233Smarkm#define BKTR_SOL      0x2	/* first dword */
257124087Sfsmp
257224246Sfsmp#define OP_WRITE      (0x1 << 28)
257325329Sfsmp#define OP_SKIP       (0x2 << 28)
257424246Sfsmp#define OP_WRITEC     (0x5 << 28)
257524246Sfsmp#define OP_JUMP	      (0x7 << 28)
257624246Sfsmp#define OP_SYNC	      (0x8 << 28)
257724246Sfsmp#define OP_WRITE123   (0x9 << 28)
257824246Sfsmp#define OP_WRITES123  (0xb << 28)
257929233Smarkm#define OP_SOL	      (1 << 27)		/* first instr for scanline */
258024246Sfsmp#define OP_EOL	      (1 << 26)
258124087Sfsmp
258246176Sroger#define BKTR_RESYNC   (1 << 15)
258346176Sroger#define BKTR_GEN_IRQ  (1 << 24)
258447439Sroger
258547439Sroger/*
258647439Sroger * The RISC status bits can be set/cleared in the RISC programs
258747439Sroger * and tested in the Interrupt Handler
258847439Sroger */
258947439Sroger#define BKTR_SET_RISC_STATUS_BIT0 (1 << 16)
259047439Sroger#define BKTR_SET_RISC_STATUS_BIT1 (1 << 17)
259147439Sroger#define BKTR_SET_RISC_STATUS_BIT2 (1 << 18)
259247439Sroger#define BKTR_SET_RISC_STATUS_BIT3 (1 << 19)
259347439Sroger
259447439Sroger#define BKTR_CLEAR_RISC_STATUS_BIT0 (1 << 20)
259547439Sroger#define BKTR_CLEAR_RISC_STATUS_BIT1 (1 << 21)
259647439Sroger#define BKTR_CLEAR_RISC_STATUS_BIT2 (1 << 22)
259747439Sroger#define BKTR_CLEAR_RISC_STATUS_BIT3 (1 << 23)
259847439Sroger
259947439Sroger#define BKTR_TEST_RISC_STATUS_BIT0 (1 << 28)
260047439Sroger#define BKTR_TEST_RISC_STATUS_BIT1 (1 << 29)
260147439Sroger#define BKTR_TEST_RISC_STATUS_BIT2 (1 << 30)
2602261455Seadler#define BKTR_TEST_RISC_STATUS_BIT3 (1U << 31)
260347439Sroger
2604104094Sphkstatic bool_t notclipped (bktr_reg_t * bktr, int x, int width) {
260525329Sfsmp    int i;
260625329Sfsmp    bktr_clip_t * clip_node;
260725329Sfsmp    bktr->clip_start = -1;
260825329Sfsmp    bktr->last_y = 0;
260925329Sfsmp    bktr->y = 0;
261025329Sfsmp    bktr->y2 = width;
261125329Sfsmp    bktr->line_length = width;
261225329Sfsmp    bktr->yclip = -1;
261325329Sfsmp    bktr->yclip2 = -1;
261425329Sfsmp    bktr->current_col = 0;
261525329Sfsmp
261625329Sfsmp    if (bktr->max_clip_node == 0 ) return TRUE;
261725329Sfsmp    clip_node = (bktr_clip_t *) &bktr->clip_list[0];
261825329Sfsmp
261925329Sfsmp
262025329Sfsmp    for (i = 0; i < bktr->max_clip_node; i++ ) {
262125329Sfsmp	clip_node = (bktr_clip_t *) &bktr->clip_list[i];
262225329Sfsmp	if (x >= clip_node->x_min && x <= clip_node->x_max  ) {
262325329Sfsmp	    bktr->clip_start = i;
262425329Sfsmp	    return FALSE;
262525329Sfsmp	}
262625329Sfsmp    }
262725329Sfsmp
262825329Sfsmp    return TRUE;
262925329Sfsmp}
263025329Sfsmp
2631104094Sphkstatic bool_t getline(bktr_reg_t *bktr, int x ) {
263225329Sfsmp    int i, j;
263325329Sfsmp    bktr_clip_t * clip_node ;
263425329Sfsmp
263525329Sfsmp    if (bktr->line_length == 0 ||
263625329Sfsmp	bktr->current_col >= bktr->line_length) return FALSE;
263725329Sfsmp
263825329Sfsmp    bktr->y = min(bktr->last_y, bktr->line_length);
263925329Sfsmp    bktr->y2 = bktr->line_length;
264025329Sfsmp
264125329Sfsmp    bktr->yclip = bktr->yclip2 = -1;
264225329Sfsmp    for (i = bktr->clip_start; i < bktr->max_clip_node; i++ ) {
264325329Sfsmp	clip_node = (bktr_clip_t *) &bktr->clip_list[i];
264425329Sfsmp	if (x >= clip_node->x_min && x <= clip_node->x_max) {
264525329Sfsmp	    if (bktr->last_y <= clip_node->y_min) {
264625329Sfsmp		bktr->y =      min(bktr->last_y, bktr->line_length);
264725329Sfsmp		bktr->y2 =     min(clip_node->y_min, bktr->line_length);
264825329Sfsmp		bktr->yclip =  min(clip_node->y_min, bktr->line_length);
264925329Sfsmp		bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
265025329Sfsmp		bktr->last_y = bktr->yclip2;
265125329Sfsmp		bktr->clip_start = i;
265225329Sfsmp
265325329Sfsmp		for (j = i+1; j  < bktr->max_clip_node; j++ ) {
265425329Sfsmp		    clip_node = (bktr_clip_t *) &bktr->clip_list[j];
265525329Sfsmp		    if (x >= clip_node->x_min && x <= clip_node->x_max) {
265625329Sfsmp			if (bktr->last_y >= clip_node->y_min) {
265725329Sfsmp			    bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
265825329Sfsmp			    bktr->last_y = bktr->yclip2;
265925329Sfsmp			    bktr->clip_start = j;
266025329Sfsmp			}
266125329Sfsmp		    } else break  ;
266225329Sfsmp		}
266325329Sfsmp		return TRUE;
266425329Sfsmp	    }
266525329Sfsmp	}
266625329Sfsmp    }
266725329Sfsmp
266825329Sfsmp    if (bktr->current_col <= bktr->line_length) {
266925329Sfsmp	bktr->current_col = bktr->line_length;
267025329Sfsmp	return TRUE;
267125329Sfsmp    }
267225329Sfsmp    return FALSE;
267325329Sfsmp}
267425329Sfsmp
2675139941Scognetstatic bool_t split(bktr_reg_t * bktr, volatile uint32_t **dma_prog, int width ,
267625329Sfsmp		    u_long operation, int pixel_width,
267725329Sfsmp		    volatile u_char ** target_buffer, int cols ) {
267825329Sfsmp
267925329Sfsmp u_long flag, flag2;
268031186Sahasty struct meteor_pixfmt *pf = &pixfmt_table[ bktr->pixfmt ].public;
268131186Sahasty u_int  skip, start_skip;
268231186Sahasty
268331186Sahasty  /*  For RGB24, we need to align the component in FIFO Byte Lane 0         */
268431186Sahasty  /*    to the 1st byte in the mem dword containing our start addr.         */
268531186Sahasty  /*    BTW, we know this pixfmt's 1st byte is Blue; thus the start addr    */
268631186Sahasty  /*     must be Blue.                                                      */
268731186Sahasty  start_skip = 0;
268831186Sahasty  if (( pf->type == METEOR_PIXTYPE_RGB ) && ( pf->Bpp == 3 ))
268943311Sdillon	  switch ( ((uintptr_t) (volatile void *) *target_buffer) % 4 ) {
269031186Sahasty	  case 2 : start_skip = 4 ; break;
269131186Sahasty	  case 1 : start_skip = 8 ; break;
269231186Sahasty	  }
269331186Sahasty
269425329Sfsmp if ((width * pixel_width) < DMA_BT848_SPLIT ) {
269525329Sfsmp     if (  width == cols) {
269625329Sfsmp	 flag = OP_SOL | OP_EOL;
269725329Sfsmp       } else if (bktr->current_col == 0 ) {
269825329Sfsmp	    flag  = OP_SOL;
269954314Sroger       } else if (bktr->current_col == cols) {
270025329Sfsmp	    flag = OP_EOL;
270125329Sfsmp       } else flag = 0;
270225329Sfsmp
270331186Sahasty     skip = 0;
270431186Sahasty     if (( flag & OP_SOL ) && ( start_skip > 0 )) {
270531186Sahasty	     *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip;
270631186Sahasty	     flag &= ~OP_SOL;
270731186Sahasty	     skip = start_skip;
270831186Sahasty     }
270931186Sahasty
271031186Sahasty     *(*dma_prog)++ = operation | flag  | (width * pixel_width - skip);
271125329Sfsmp     if (operation != OP_SKIP )
271243311Sdillon	 *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer;
271325329Sfsmp
271425329Sfsmp     *target_buffer += width * pixel_width;
271525329Sfsmp     bktr->current_col += width;
271625329Sfsmp
271731186Sahasty } else {
271825329Sfsmp
271925329Sfsmp	if (bktr->current_col == 0 && width == cols) {
272025329Sfsmp	    flag = OP_SOL ;
272125329Sfsmp	    flag2 = OP_EOL;
272225329Sfsmp        } else if (bktr->current_col == 0 ) {
272325329Sfsmp	    flag = OP_SOL;
272425329Sfsmp	    flag2 = 0;
272554314Sroger	} else if (bktr->current_col >= cols)  {
272625329Sfsmp	    flag =  0;
272725329Sfsmp	    flag2 = OP_EOL;
272825329Sfsmp	} else {
272925329Sfsmp	    flag =  0;
273025329Sfsmp	    flag2 = 0;
273125329Sfsmp	}
273231186Sahasty
273331186Sahasty	skip = 0;
273431186Sahasty	if (( flag & OP_SOL ) && ( start_skip > 0 )) {
273531186Sahasty		*(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip;
273631186Sahasty		flag &= ~OP_SOL;
273731186Sahasty		skip = start_skip;
273831186Sahasty	}
273931186Sahasty
274031186Sahasty	*(*dma_prog)++ = operation  | flag |
274131186Sahasty	      (width * pixel_width / 2 - skip);
274225329Sfsmp	if (operation != OP_SKIP )
274343311Sdillon	      *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer ;
274425329Sfsmp	*target_buffer +=  (width * pixel_width / 2) ;
274525329Sfsmp
274631186Sahasty	if ( operation == OP_WRITE )
274731186Sahasty		operation = OP_WRITEC;
274829233Smarkm	*(*dma_prog)++ = operation | flag2 |
274925329Sfsmp	    (width * pixel_width / 2);
275025329Sfsmp	*target_buffer +=  (width * pixel_width / 2) ;
275125329Sfsmp	  bktr->current_col += width;
275225329Sfsmp
275325329Sfsmp    }
275425329Sfsmp return TRUE;
275525329Sfsmp}
275625329Sfsmp
275725329Sfsmp
275847439Sroger/*
275947439Sroger * Generate the RISC instructions to capture both VBI and video images
276047439Sroger */
276147439Srogerstatic void
276247439Srogerrgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace )
276347439Sroger{
276447439Sroger	int			i;
2765139941Scognet	volatile uint32_t	target_buffer, buffer, target,width;
2766139941Scognet	volatile uint32_t	pitch;
2767139941Scognet	volatile uint32_t	*dma_prog;	/* DMA prog is an array of
276851356Sroger						32 bit RISC instructions */
2769139941Scognet	volatile uint32_t	*loop_point;
277047439Sroger        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
277147439Sroger	u_int                   Bpp = pf_int->public.Bpp;
277247439Sroger	unsigned int            vbisamples;     /* VBI samples per line */
277347439Sroger	unsigned int            vbilines;       /* VBI lines per field */
277447439Sroger	unsigned int            num_dwords;     /* DWORDS per line */
277525329Sfsmp
277647439Sroger	vbisamples = format_params[bktr->format_params].vbi_num_samples;
277747439Sroger	vbilines   = format_params[bktr->format_params].vbi_num_lines;
277847439Sroger	num_dwords = vbisamples/4;
277925329Sfsmp
278059014Sroger	OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
278159014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
278259014Sroger	OUTB(bktr, BKTR_VBI_PACK_SIZE, ((num_dwords)) & 0xff);
278359014Sroger	OUTB(bktr, BKTR_VBI_PACK_DEL, ((num_dwords)>> 8) & 0x01); /* no hdelay    */
278459014Sroger							    /* no ext frame */
278547439Sroger
278659014Sroger	OUTB(bktr, BKTR_OFORM, 0x00);
278747439Sroger
278859014Sroger 	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */
278959014Sroger 	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40);
279059014Sroger	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
279159014Sroger	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
279247439Sroger
279347439Sroger 	/* disable gamma correction removal */
279459014Sroger 	OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
279547439Sroger
279647439Sroger	if (cols > 385 ) {
279759014Sroger	    OUTB(bktr, BKTR_E_VTC, 0);
279859014Sroger	    OUTB(bktr, BKTR_O_VTC, 0);
279947439Sroger	} else {
280059014Sroger	    OUTB(bktr, BKTR_E_VTC, 1);
280159014Sroger	    OUTB(bktr, BKTR_O_VTC, 1);
280247439Sroger	}
280347439Sroger	bktr->capcontrol = 3 << 2 |  3;
280447439Sroger
2805139941Scognet	dma_prog = (uint32_t *) bktr->dma_prog;
280647439Sroger
280747439Sroger	/* Construct Write */
280847439Sroger
280947439Sroger	if (bktr->video.addr) {
281047439Sroger		target_buffer = (u_long) bktr->video.addr;
281147439Sroger		pitch = bktr->video.width;
281247439Sroger	}
281347439Sroger	else {
281447439Sroger		target_buffer = (u_long) vtophys(bktr->bigbuf);
281547439Sroger		pitch = cols*Bpp;
281647439Sroger	}
281747439Sroger
281847439Sroger	buffer = target_buffer;
281947439Sroger
282050693Sroger	/* Wait for the VRE sync marking the end of the Even and
282150693Sroger	 * the start of the Odd field. Resync here.
282250693Sroger	 */
282350693Sroger	*dma_prog++ = OP_SYNC | BKTR_RESYNC |BKTR_VRE;
282450693Sroger	*dma_prog++ = 0;
282547439Sroger
282650693Sroger	loop_point = dma_prog;
282750693Sroger
282847439Sroger	/* store the VBI data */
282947439Sroger	/* look for sync with packed data */
283050693Sroger	*dma_prog++ = OP_SYNC | BKTR_FM1;
283147439Sroger	*dma_prog++ = 0;
283247439Sroger	for(i = 0; i < vbilines; i++) {
283347439Sroger		*dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples;
283462112Sroger		*dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata +
283547439Sroger					(i * VBI_LINE_SIZE));
283647439Sroger	}
283747439Sroger
283850693Sroger	if ( (i_flag == 2/*Odd*/) || (i_flag==3) /*interlaced*/ ) {
283950693Sroger		/* store the Odd field video image */
284050693Sroger		/* look for sync with packed data */
284150693Sroger		*dma_prog++ = OP_SYNC  | BKTR_FM1;
284250693Sroger		*dma_prog++ = 0;  /* NULL WORD */
284350693Sroger		width = cols;
284454314Sroger		for (i = 0; i < (rows/interlace); i++) {
284550693Sroger		    target = target_buffer;
284650693Sroger		    if ( notclipped(bktr, i, width)) {
2847139941Scognet			split(bktr, (volatile uint32_t **) &dma_prog,
284847439Sroger			      bktr->y2 - bktr->y, OP_WRITE,
284997208Speter			      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
285050693Sroger
285150693Sroger		    } else {
285250693Sroger			while(getline(bktr, i)) {
285350693Sroger			    if (bktr->y != bktr->y2 ) {
2854139941Scognet				split(bktr, (volatile uint32_t **) &dma_prog,
285550693Sroger				      bktr->y2 - bktr->y, OP_WRITE,
285697208Speter				      Bpp, (volatile u_char **)(uintptr_t)&target, cols);
285750693Sroger			    }
285850693Sroger			    if (bktr->yclip != bktr->yclip2 ) {
2859139941Scognet				split(bktr,(volatile uint32_t **) &dma_prog,
286050693Sroger				      bktr->yclip2 - bktr->yclip,
286150693Sroger				      OP_SKIP,
286297208Speter				      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
286350693Sroger			    }
286450693Sroger			}
286550693Sroger
286647439Sroger		    }
286750693Sroger
286850693Sroger		    target_buffer += interlace * pitch;
286950693Sroger
287047439Sroger		}
287147439Sroger
287250693Sroger	} /* end if */
287347439Sroger
287450693Sroger	/* Grab the Even field */
287550693Sroger	/* Look for the VRO, end of Odd field, marker */
287650693Sroger	*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
287750693Sroger	*dma_prog++ = 0;  /* NULL WORD */
287847439Sroger
287950693Sroger	/* store the VBI data */
288050693Sroger	/* look for sync with packed data */
288150693Sroger	*dma_prog++ = OP_SYNC | BKTR_FM1;
288250693Sroger	*dma_prog++ = 0;
288350693Sroger	for(i = 0; i < vbilines; i++) {
288450693Sroger		*dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples;
288562112Sroger		*dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata +
288650693Sroger				((i+MAX_VBI_LINES) * VBI_LINE_SIZE));
288747439Sroger	}
288847439Sroger
288950693Sroger	/* store the video image */
289050693Sroger	if (i_flag == 1) /*Even Only*/
289150693Sroger	        target_buffer = buffer;
289250693Sroger	if (i_flag == 3) /*interlaced*/
289350693Sroger	        target_buffer = buffer+pitch;
289447439Sroger
289547439Sroger
289650693Sroger	if ((i_flag == 1) /*Even Only*/ || (i_flag==3) /*interlaced*/) {
289747439Sroger		/* look for sync with packed data */
289850693Sroger		*dma_prog++ = OP_SYNC | BKTR_FM1;
289947439Sroger		*dma_prog++ = 0;  /* NULL WORD */
290047439Sroger		width = cols;
290154314Sroger		for (i = 0; i < (rows/interlace); i++) {
290247439Sroger		    target = target_buffer;
290347439Sroger		    if ( notclipped(bktr, i, width)) {
2904139941Scognet			split(bktr, (volatile uint32_t **) &dma_prog,
290547439Sroger			      bktr->y2 - bktr->y, OP_WRITE,
290697208Speter			      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
290747439Sroger		    } else {
290847439Sroger			while(getline(bktr, i)) {
290947439Sroger			    if (bktr->y != bktr->y2 ) {
2910139941Scognet				split(bktr, (volatile uint32_t **) &dma_prog,
291147439Sroger				      bktr->y2 - bktr->y, OP_WRITE,
291297208Speter				      Bpp, (volatile u_char **)(uintptr_t)&target,
291347439Sroger				      cols);
291447439Sroger			    }
291547439Sroger			    if (bktr->yclip != bktr->yclip2 ) {
2916139941Scognet				split(bktr, (volatile uint32_t **) &dma_prog,
291747439Sroger				      bktr->yclip2 - bktr->yclip, OP_SKIP,
291897208Speter				      Bpp, (volatile u_char **)(uintptr_t) &target,  cols);
291947439Sroger			    }
292047439Sroger
292147439Sroger			}
292247439Sroger
292347439Sroger		    }
292447439Sroger
292547439Sroger		    target_buffer += interlace * pitch;
292647439Sroger
292747439Sroger		}
292847439Sroger	}
292947439Sroger
293047439Sroger	/* Look for end of 'Even Field' */
293147439Sroger	*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
293247439Sroger	*dma_prog++ = 0;  /* NULL WORD */
293347439Sroger
293447439Sroger	*dma_prog++ = OP_JUMP ;
293550693Sroger	*dma_prog++ = (u_long ) vtophys(loop_point) ;
293647439Sroger	*dma_prog++ = 0;  /* NULL WORD */
293747439Sroger
293847439Sroger}
293947439Sroger
294047439Sroger
294147439Sroger
294247439Sroger
294324087Sfsmpstatic void
294425329Sfsmprgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace )
294524087Sfsmp{
294624087Sfsmp	int			i;
2947139941Scognet	volatile uint32_t		target_buffer, buffer, target,width;
2948139941Scognet	volatile uint32_t	pitch;
2949139941Scognet	volatile  uint32_t	*dma_prog;
295025329Sfsmp        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
295125329Sfsmp	u_int                   Bpp = pf_int->public.Bpp;
295224087Sfsmp
295359014Sroger	OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
295459014Sroger	OUTB(bktr, BKTR_VBI_PACK_SIZE, 0);
295559014Sroger	OUTB(bktr, BKTR_VBI_PACK_DEL, 0);
295659014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
295724087Sfsmp
295859014Sroger	OUTB(bktr, BKTR_OFORM, 0x00);
295924087Sfsmp
296059014Sroger 	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */
296159014Sroger 	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40);
296259014Sroger	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
296359014Sroger	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
296436090Sahasty
296536090Sahasty 	/* disable gamma correction removal */
296659014Sroger	OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
296736090Sahasty
296825329Sfsmp	if (cols > 385 ) {
296959014Sroger	    OUTB(bktr, BKTR_E_VTC, 0);
297059014Sroger	    OUTB(bktr, BKTR_O_VTC, 0);
297125329Sfsmp	} else {
297259014Sroger	    OUTB(bktr, BKTR_E_VTC, 1);
297359014Sroger	    OUTB(bktr, BKTR_O_VTC, 1);
297425329Sfsmp	}
297524087Sfsmp	bktr->capcontrol = 3 << 2 |  3;
297623599Smarkm
2977139941Scognet	dma_prog = (uint32_t *) bktr->dma_prog;
297823599Smarkm
297924087Sfsmp	/* Construct Write */
298023599Smarkm
298124087Sfsmp	if (bktr->video.addr) {
2982139941Scognet		target_buffer = (uint32_t) bktr->video.addr;
298324087Sfsmp		pitch = bktr->video.width;
298424087Sfsmp	}
298524087Sfsmp	else {
2986139941Scognet		target_buffer = (uint32_t) vtophys(bktr->bigbuf);
298725329Sfsmp		pitch = cols*Bpp;
298824087Sfsmp	}
298923599Smarkm
299024087Sfsmp	buffer = target_buffer;
299124087Sfsmp
299224087Sfsmp	/* contruct sync : for video packet format */
299346176Sroger	*dma_prog++ = OP_SYNC  | BKTR_RESYNC | BKTR_FM1;
299424087Sfsmp
299524087Sfsmp	/* sync, mode indicator packed data */
299624087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
299725329Sfsmp	width = cols;
299854314Sroger	for (i = 0; i < (rows/interlace); i++) {
299925329Sfsmp	    target = target_buffer;
300025329Sfsmp	    if ( notclipped(bktr, i, width)) {
3001139941Scognet		split(bktr, (volatile uint32_t **) &dma_prog,
300225329Sfsmp		      bktr->y2 - bktr->y, OP_WRITE,
300397208Speter		      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
300424087Sfsmp
300525329Sfsmp	    } else {
300625329Sfsmp		while(getline(bktr, i)) {
300725329Sfsmp		    if (bktr->y != bktr->y2 ) {
3008139941Scognet			split(bktr, (volatile uint32_t **) &dma_prog,
300925329Sfsmp			      bktr->y2 - bktr->y, OP_WRITE,
301097208Speter			      Bpp, (volatile u_char **)(uintptr_t)&target, cols);
301125329Sfsmp		    }
301225329Sfsmp		    if (bktr->yclip != bktr->yclip2 ) {
3013139941Scognet			split(bktr,(volatile uint32_t **) &dma_prog,
301425329Sfsmp			      bktr->yclip2 - bktr->yclip,
301525329Sfsmp			      OP_SKIP,
301697208Speter			      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
301725329Sfsmp		    }
301825329Sfsmp		}
301925329Sfsmp
302025329Sfsmp	    }
302125329Sfsmp
302225329Sfsmp	    target_buffer += interlace * pitch;
302325329Sfsmp
302424087Sfsmp	}
302524087Sfsmp
302624087Sfsmp	switch (i_flag) {
302724087Sfsmp	case 1:
302824087Sfsmp		/* sync vre */
302946176Sroger		*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO;
303024087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
303124087Sfsmp
303233025Sahasty		*dma_prog++ = OP_JUMP;
3033139941Scognet		*dma_prog++ = (uint32_t ) vtophys(bktr->dma_prog);
303424087Sfsmp		return;
303524087Sfsmp
303624087Sfsmp	case 2:
303725329Sfsmp		/* sync vro */
303846176Sroger		*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRE;
303924087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
304024087Sfsmp
304124087Sfsmp		*dma_prog++ = OP_JUMP;
3042139941Scognet		*dma_prog++ = (uint32_t ) vtophys(bktr->dma_prog);
304324087Sfsmp		return;
304424087Sfsmp
304524087Sfsmp	case 3:
304625329Sfsmp		/* sync vro */
304746176Sroger		*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
304824087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
304933025Sahasty		*dma_prog++ = OP_JUMP; ;
3050139941Scognet		*dma_prog = (uint32_t ) vtophys(bktr->odd_dma_prog);
305124087Sfsmp		break;
305224087Sfsmp	}
305324087Sfsmp
305424087Sfsmp	if (interlace == 2) {
305524087Sfsmp
305633025Sahasty	        target_buffer = buffer + pitch;
305733025Sahasty
3058139941Scognet		dma_prog = (uint32_t *) bktr->odd_dma_prog;
305924087Sfsmp
306024087Sfsmp		/* sync vre IRQ bit */
306146176Sroger		*dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
306224087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
306325329Sfsmp                width = cols;
306454314Sroger		for (i = 0; i < (rows/interlace); i++) {
306525329Sfsmp		    target = target_buffer;
306625329Sfsmp		    if ( notclipped(bktr, i, width)) {
3067139941Scognet			split(bktr, (volatile uint32_t **) &dma_prog,
306825329Sfsmp			      bktr->y2 - bktr->y, OP_WRITE,
306997208Speter			      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
307025329Sfsmp		    } else {
307125329Sfsmp			while(getline(bktr, i)) {
307225329Sfsmp			    if (bktr->y != bktr->y2 ) {
3073139941Scognet				split(bktr, (volatile uint32_t **) &dma_prog,
307425329Sfsmp				      bktr->y2 - bktr->y, OP_WRITE,
307597208Speter				      Bpp, (volatile u_char **)(uintptr_t)&target,
307625329Sfsmp				      cols);
307725329Sfsmp			    }
307825329Sfsmp			    if (bktr->yclip != bktr->yclip2 ) {
3079139941Scognet				split(bktr, (volatile uint32_t **) &dma_prog,
308025329Sfsmp				      bktr->yclip2 - bktr->yclip, OP_SKIP,
308197208Speter				      Bpp, (volatile u_char **)(uintptr_t)&target,  cols);
308225329Sfsmp			    }
308324087Sfsmp
308425329Sfsmp			}
308525329Sfsmp
308625329Sfsmp		    }
308725329Sfsmp
308825329Sfsmp		    target_buffer += interlace * pitch;
308925329Sfsmp
309024087Sfsmp		}
309124087Sfsmp	}
309224087Sfsmp
309324087Sfsmp	/* sync vre IRQ bit */
309446176Sroger	*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
309524087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
309624991Sfsmp	*dma_prog++ = OP_JUMP ;
3097139941Scognet	*dma_prog++ = (uint32_t ) vtophys(bktr->dma_prog) ;
309824087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
309924087Sfsmp}
310024087Sfsmp
310124087Sfsmp
310224087Sfsmp/*
310324087Sfsmp *
310424087Sfsmp */
310524087Sfsmpstatic void
310624528Sfsmpyuvpack_prog( bktr_ptr_t bktr, char i_flag,
310724087Sfsmp	      int cols, int rows, int interlace )
310824087Sfsmp{
310924087Sfsmp	int			i;
311024087Sfsmp	volatile unsigned int	inst;
311124087Sfsmp	volatile unsigned int	inst3;
3112139941Scognet	volatile uint32_t	target_buffer, buffer;
3113139941Scognet	volatile  uint32_t	*dma_prog;
311429233Smarkm        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
311524087Sfsmp	int			b;
311624087Sfsmp
311759014Sroger	OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
311824087Sfsmp
311959014Sroger	OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC); /* enable chroma comb */
312059014Sroger	OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC);
312124087Sfsmp
312259014Sroger	OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_RGB_DED | BT848_COLOR_CTL_GAMMA);
312359014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
312424087Sfsmp
312524087Sfsmp	bktr->capcontrol =   1 << 6 | 1 << 4 | 1 << 2 | 3;
312629233Smarkm	bktr->capcontrol = 3 << 2 |  3;
312724087Sfsmp
3128139941Scognet	dma_prog = (uint32_t *) bktr->dma_prog;
312924087Sfsmp
313024087Sfsmp	/* Construct Write */
313124087Sfsmp
313224087Sfsmp	/* write , sol, eol */
313329233Smarkm	inst = OP_WRITE	 | OP_SOL | (cols);
313424087Sfsmp	/* write , sol, eol */
313529233Smarkm	inst3 = OP_WRITE | OP_EOL | (cols);
313624087Sfsmp
313724087Sfsmp	if (bktr->video.addr)
3138139941Scognet		target_buffer = (uint32_t) bktr->video.addr;
313924087Sfsmp	else
3140139941Scognet		target_buffer = (uint32_t) vtophys(bktr->bigbuf);
314124087Sfsmp
314224087Sfsmp	buffer = target_buffer;
314324087Sfsmp
314424087Sfsmp	/* contruct sync : for video packet format */
314524087Sfsmp	/* sync, mode indicator packed data */
3146107668Sroger	*dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
314724087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
314824087Sfsmp
314924087Sfsmp	b = cols;
315024087Sfsmp
315124087Sfsmp	for (i = 0; i < (rows/interlace); i++) {
315224087Sfsmp		*dma_prog++ = inst;
315324087Sfsmp		*dma_prog++ = target_buffer;
315424087Sfsmp		*dma_prog++ = inst3;
315524087Sfsmp		*dma_prog++ = target_buffer + b;
315624087Sfsmp		target_buffer += interlace*(cols * 2);
315724087Sfsmp	}
315824087Sfsmp
315924087Sfsmp	switch (i_flag) {
316024087Sfsmp	case 1:
316124087Sfsmp		/* sync vre */
3162107668Sroger		*dma_prog++ = OP_SYNC  | BKTR_GEN_IRQ | BKTR_VRE;
316324087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
316424087Sfsmp
316524087Sfsmp		*dma_prog++ = OP_JUMP;
3166139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
316724087Sfsmp		return;
316824087Sfsmp
316924087Sfsmp	case 2:
317025329Sfsmp		/* sync vro */
3171107668Sroger		*dma_prog++ = OP_SYNC  | BKTR_GEN_IRQ | BKTR_VRO;
317224087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
317324087Sfsmp		*dma_prog++ = OP_JUMP;
3174139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
317524087Sfsmp		return;
317624087Sfsmp
317724087Sfsmp	case 3:
317833025Sahasty		/* sync vro */
3179107668Sroger		*dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
318024087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
318124087Sfsmp		*dma_prog++ = OP_JUMP  ;
3182139941Scognet		*dma_prog = (uint32_t) vtophys(bktr->odd_dma_prog);
318324087Sfsmp		break;
318424087Sfsmp	}
318524087Sfsmp
318624087Sfsmp	if (interlace == 2) {
318724087Sfsmp
3188139941Scognet		target_buffer =	 (uint32_t) buffer + cols*2;
318924087Sfsmp
3190139941Scognet		dma_prog = (uint32_t *) bktr->odd_dma_prog;
319124087Sfsmp
319224087Sfsmp		/* sync vre */
3193107668Sroger		*dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
319424087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
319524087Sfsmp
319624087Sfsmp		for (i = 0; i < (rows/interlace) ; i++) {
319724087Sfsmp			*dma_prog++ = inst;
319824087Sfsmp			*dma_prog++ = target_buffer;
319924087Sfsmp			*dma_prog++ = inst3;
320024087Sfsmp			*dma_prog++ = target_buffer + b;
320124087Sfsmp			target_buffer += interlace * ( cols*2);
320224087Sfsmp		}
320324087Sfsmp	}
320424087Sfsmp
320525329Sfsmp	/* sync vro IRQ bit */
3206107668Sroger	*dma_prog++ = OP_SYNC   |  BKTR_GEN_IRQ  | BKTR_RESYNC |  BKTR_VRE;
320724087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
320829233Smarkm	*dma_prog++ = OP_JUMP ;
3209139941Scognet	*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
321024087Sfsmp
321124087Sfsmp	*dma_prog++ = OP_JUMP;
3212139941Scognet	*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
321324087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
321424087Sfsmp}
321524087Sfsmp
321624087Sfsmp
321724087Sfsmp/*
321824087Sfsmp *
321924087Sfsmp */
322024087Sfsmpstatic void
322124528Sfsmpyuv422_prog( bktr_ptr_t bktr, char i_flag,
322224087Sfsmp	     int cols, int rows, int interlace ){
322324087Sfsmp
322429233Smarkm	int			i;
322524087Sfsmp	volatile unsigned int	inst;
3226139941Scognet	volatile uint32_t	target_buffer, t1, buffer;
3227139941Scognet	volatile uint32_t	*dma_prog;
322829233Smarkm        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
322924087Sfsmp
323059014Sroger	OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
323129233Smarkm
3232139941Scognet	dma_prog = (uint32_t*) bktr->dma_prog;
323324087Sfsmp
323424087Sfsmp	bktr->capcontrol =   1 << 6 | 1 << 4 |	3;
323524087Sfsmp
323659014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
323759014Sroger	OUTB(bktr, BKTR_OFORM, 0x00);
323824087Sfsmp
323959014Sroger	OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_LDEC); /* disable luma decimation */
324059014Sroger	OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_LDEC);
324124087Sfsmp
324259014Sroger	OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC);	/* chroma agc enable */
324359014Sroger	OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC);
324424087Sfsmp
324559014Sroger	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
324659014Sroger	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
3247116108Sfjoe	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */
3248116108Sfjoe	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40);
324924087Sfsmp
325024528Sfsmp	/* disable gamma correction removal */
325159014Sroger	OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
325224087Sfsmp
325324087Sfsmp	/* Construct Write */
325429233Smarkm	inst  = OP_WRITE123  | OP_SOL | OP_EOL |  (cols);
325524087Sfsmp	if (bktr->video.addr)
3256139941Scognet		target_buffer = (uint32_t) bktr->video.addr;
325724087Sfsmp	else
3258139941Scognet		target_buffer = (uint32_t) vtophys(bktr->bigbuf);
325924087Sfsmp
326024087Sfsmp	buffer = target_buffer;
326124087Sfsmp
326233025Sahasty	t1 = buffer;
326324087Sfsmp
326424087Sfsmp	/* contruct sync : for video packet format */
326524991Sfsmp	*dma_prog++ = OP_SYNC  | 1 << 15 |	BKTR_FM3; /*sync, mode indicator packed data*/
326624087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
326724087Sfsmp
326833025Sahasty	for (i = 0; i < (rows/interlace ) ; i++) {
326924087Sfsmp		*dma_prog++ = inst;
327024087Sfsmp		*dma_prog++ = cols/2 | cols/2 << 16;
327124087Sfsmp		*dma_prog++ = target_buffer;
327224087Sfsmp		*dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
327324087Sfsmp		*dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace;
327424087Sfsmp		target_buffer += interlace*cols;
327524087Sfsmp	}
327624087Sfsmp
327724087Sfsmp	switch (i_flag) {
327824087Sfsmp	case 1:
327933025Sahasty		*dma_prog++ = OP_SYNC  | 1 << 24 | BKTR_VRE;  /*sync vre*/
328024087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
328124087Sfsmp
328233025Sahasty		*dma_prog++ = OP_JUMP ;
3283139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
328424087Sfsmp		return;
328524528Sfsmp
328624087Sfsmp	case 2:
328733025Sahasty		*dma_prog++ = OP_SYNC  | 1 << 24 | BKTR_VRO;  /*sync vre*/
328824087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
328924087Sfsmp
329024087Sfsmp		*dma_prog++ = OP_JUMP;
3291139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
329224087Sfsmp		return;
329324528Sfsmp
329424087Sfsmp	case 3:
329533025Sahasty		*dma_prog++ = OP_SYNC	| 1 << 24 |  1 << 15 |   BKTR_VRO;
329624087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
329724087Sfsmp
329824991Sfsmp		*dma_prog++ = OP_JUMP  ;
3299139941Scognet		*dma_prog = (uint32_t) vtophys(bktr->odd_dma_prog);
330024087Sfsmp		break;
330124087Sfsmp	}
330224087Sfsmp
330324087Sfsmp	if (interlace == 2) {
330424087Sfsmp
3305139941Scognet		dma_prog = (uint32_t *) bktr->odd_dma_prog;
330624087Sfsmp
3307139941Scognet		target_buffer  = (uint32_t) buffer + cols;
330833025Sahasty		t1 = buffer + cols/2;
330924991Sfsmp		*dma_prog++ = OP_SYNC	|   1 << 15 | BKTR_FM3;
331024087Sfsmp		*dma_prog++ = 0;  /* NULL WORD */
331124087Sfsmp
331233025Sahasty		for (i = 0; i < (rows/interlace )  ; i++) {
331324087Sfsmp			*dma_prog++ = inst;
331424087Sfsmp			*dma_prog++ = cols/2 | cols/2 << 16;
331524087Sfsmp			*dma_prog++ = target_buffer;
331624087Sfsmp			*dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
331724087Sfsmp			*dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace;
331824087Sfsmp			target_buffer += interlace*cols;
331924087Sfsmp		}
332024087Sfsmp	}
332124087Sfsmp
332233025Sahasty	*dma_prog++ = OP_SYNC  | 1 << 24 | 1 << 15 |   BKTR_VRE;
332324087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
332424991Sfsmp	*dma_prog++ = OP_JUMP ;
3325139941Scognet	*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog) ;
332624087Sfsmp	*dma_prog++ = 0;  /* NULL WORD */
332724087Sfsmp}
332824087Sfsmp
332924087Sfsmp
333024087Sfsmp/*
333124087Sfsmp *
333224087Sfsmp */
333324087Sfsmpstatic void
333431186Sahastyyuv12_prog( bktr_ptr_t bktr, char i_flag,
333531186Sahasty	     int cols, int rows, int interlace ){
333631186Sahasty
333733025Sahasty	int			i;
333831186Sahasty	volatile unsigned int	inst;
333931186Sahasty	volatile unsigned int	inst1;
3340139941Scognet	volatile uint32_t	target_buffer, t1, buffer;
3341139941Scognet	volatile uint32_t	*dma_prog;
334231186Sahasty        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
334331186Sahasty
334459014Sroger	OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
334531186Sahasty
3346139941Scognet	dma_prog = (uint32_t *) bktr->dma_prog;
334731186Sahasty
334831186Sahasty	bktr->capcontrol =   1 << 6 | 1 << 4 |	3;
334931186Sahasty
335059014Sroger	OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
335159014Sroger	OUTB(bktr, BKTR_OFORM, 0x0);
335231186Sahasty
335331186Sahasty	/* Construct Write */
335431186Sahasty 	inst  = OP_WRITE123  | OP_SOL | OP_EOL |  (cols);
335531186Sahasty 	inst1  = OP_WRITES123  | OP_SOL | OP_EOL |  (cols);
335631186Sahasty 	if (bktr->video.addr)
3357139941Scognet 		target_buffer = (uint32_t) bktr->video.addr;
335831186Sahasty 	else
3359139941Scognet 		target_buffer = (uint32_t) vtophys(bktr->bigbuf);
336031186Sahasty
336131186Sahasty	buffer = target_buffer;
336231186Sahasty 	t1 = buffer;
336331186Sahasty
336431186Sahasty 	*dma_prog++ = OP_SYNC  | 1 << 15 |	BKTR_FM3; /*sync, mode indicator packed data*/
336531186Sahasty 	*dma_prog++ = 0;  /* NULL WORD */
336631186Sahasty
336733025Sahasty 	for (i = 0; i < (rows/interlace )/2 ; i++) {
336831186Sahasty		*dma_prog++ = inst;
336931186Sahasty 		*dma_prog++ = cols/2 | (cols/2 << 16);
337031186Sahasty 		*dma_prog++ = target_buffer;
337131186Sahasty 		*dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
337231186Sahasty 		*dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace;
337331186Sahasty 		target_buffer += interlace*cols;
337431186Sahasty 		*dma_prog++ = inst1;
337531186Sahasty 		*dma_prog++ = cols/2 | (cols/2 << 16);
337631186Sahasty 		*dma_prog++ = target_buffer;
337731186Sahasty 		target_buffer += interlace*cols;
337831186Sahasty
337931186Sahasty 	}
338031186Sahasty
338131186Sahasty 	switch (i_flag) {
338231186Sahasty 	case 1:
338333025Sahasty 		*dma_prog++ = OP_SYNC  | 1 << 24 | BKTR_VRE;  /*sync vre*/
338431186Sahasty 		*dma_prog++ = 0;  /* NULL WORD */
338533025Sahasty
338633025Sahasty		*dma_prog++ = OP_JUMP;
3387139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
338831186Sahasty 		return;
338931186Sahasty
339031186Sahasty 	case 2:
339133025Sahasty 		*dma_prog++ = OP_SYNC  | 1 << 24 | BKTR_VRO;  /*sync vro*/
339231186Sahasty 		*dma_prog++ = 0;  /* NULL WORD */
339333025Sahasty
339433025Sahasty		*dma_prog++ = OP_JUMP;
3395139941Scognet		*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
339631186Sahasty 		return;
339731186Sahasty
339831186Sahasty 	case 3:
339931186Sahasty 		*dma_prog++ = OP_SYNC |  1 << 24 | 1 << 15 | BKTR_VRO;
340031186Sahasty		*dma_prog++ = 0;  /* NULL WORD */
340133025Sahasty		*dma_prog++ = OP_JUMP ;
3402139941Scognet		*dma_prog = (uint32_t) vtophys(bktr->odd_dma_prog);
340331186Sahasty		break;
340431186Sahasty	}
340531186Sahasty
340631186Sahasty	if (interlace == 2) {
340731186Sahasty
3408139941Scognet		dma_prog = (uint32_t *) bktr->odd_dma_prog;
340931186Sahasty
3410139941Scognet		target_buffer  = (uint32_t) buffer + cols;
341133025Sahasty		t1 = buffer + cols/2;
341233025Sahasty		*dma_prog++ = OP_SYNC   | 1 << 15 | BKTR_FM3;
341331186Sahasty		*dma_prog++ = 0;  /* NULL WORD */
341431186Sahasty
341531186Sahasty		for (i = 0; i < ((rows/interlace )/2 ) ; i++) {
341631186Sahasty		    *dma_prog++ = inst;
341731186Sahasty		    *dma_prog++ = cols/2 | (cols/2 << 16);
341831186Sahasty         	    *dma_prog++ = target_buffer;
341931186Sahasty		    *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
342031186Sahasty		    *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace;
342131186Sahasty		    target_buffer += interlace*cols;
342231186Sahasty		    *dma_prog++ = inst1;
342331186Sahasty		    *dma_prog++ = cols/2 | (cols/2 << 16);
342431186Sahasty		    *dma_prog++ = target_buffer;
342531186Sahasty		    target_buffer += interlace*cols;
342631186Sahasty
342731186Sahasty		}
342831186Sahasty
342931186Sahasty
343031186Sahasty	}
343131186Sahasty
343231186Sahasty	*dma_prog++ = OP_SYNC |  1 << 24 | 1 << 15 | BKTR_VRE;
343331186Sahasty	*dma_prog++ = 0;  /* NULL WORD */
343433025Sahasty	*dma_prog++ = OP_JUMP;
3435139941Scognet	*dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
343631186Sahasty	*dma_prog++ = 0;  /* NULL WORD */
343731186Sahasty}
343831186Sahasty
343931186Sahasty
344031186Sahasty
344131186Sahasty/*
344231186Sahasty *
344331186Sahasty */
344431186Sahastystatic void
344524528Sfsmpbuild_dma_prog( bktr_ptr_t bktr, char i_flag )
344624087Sfsmp{
344729233Smarkm	int			rows, cols,  interlace;
344833025Sahasty	int			tmp_int;
344933025Sahasty	unsigned int		temp;
345033025Sahasty	struct format_params	*fp;
345125329Sfsmp        struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
345233025Sahasty
345324087Sfsmp
345433025Sahasty	fp = &format_params[bktr->format_params];
345524087Sfsmp
345659014Sroger	OUTL(bktr, BKTR_INT_MASK,  ALL_INTS_DISABLED);
345759014Sroger
345824528Sfsmp	/* disable FIFO & RISC, leave other bits alone */
345959014Sroger	OUTW(bktr, BKTR_GPIO_DMA_CTL, INW(bktr, BKTR_GPIO_DMA_CTL) & ~FIFO_RISC_ENABLED);
346024528Sfsmp
346133025Sahasty	/* set video parameters */
346238706Ssos	if (bktr->capture_area_enabled)
346338706Ssos	  temp = ((quad_t ) fp->htotal* (quad_t) bktr->capture_area_x_size * 4096
346438706Ssos		  / fp->scaled_htotal / bktr->cols) -  4096;
346538706Ssos	else
346638706Ssos	  temp = ((quad_t ) fp->htotal* (quad_t) fp->scaled_hactive * 4096
346738706Ssos		  / fp->scaled_htotal / bktr->cols) -  4096;
346838706Ssos
346962112Sroger	/* printf("%s: HSCALE value is %d\n", bktr_name(bktr), temp); */
347059014Sroger	OUTB(bktr, BKTR_E_HSCALE_LO, temp & 0xff);
347159014Sroger	OUTB(bktr, BKTR_O_HSCALE_LO, temp & 0xff);
347259014Sroger	OUTB(bktr, BKTR_E_HSCALE_HI, (temp >> 8) & 0xff);
347359014Sroger	OUTB(bktr, BKTR_O_HSCALE_HI, (temp >> 8) & 0xff);
347438706Ssos
347533025Sahasty	/* horizontal active */
347633025Sahasty	temp = bktr->cols;
347762112Sroger	/* printf("%s: HACTIVE value is %d\n", bktr_name(bktr), temp); */
347859014Sroger	OUTB(bktr, BKTR_E_HACTIVE_LO, temp & 0xff);
347959014Sroger	OUTB(bktr, BKTR_O_HACTIVE_LO, temp & 0xff);
348059014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x3);
348159014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x3);
348259014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 8) & 0x3));
348359014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 8) & 0x3));
348438706Ssos
348533025Sahasty	/* horizontal delay */
348638706Ssos	if (bktr->capture_area_enabled)
348738706Ssos	  temp = ( (fp->hdelay* fp->scaled_hactive + bktr->capture_area_x_offset* fp->scaled_htotal)
348838706Ssos		 * bktr->cols) / (bktr->capture_area_x_size * fp->hactive);
348938706Ssos	else
349038706Ssos	  temp = (fp->hdelay * bktr->cols) / fp->hactive;
349138706Ssos
349233025Sahasty	temp = temp & 0x3fe;
349338706Ssos
349462112Sroger	/* printf("%s: HDELAY value is %d\n", bktr_name(bktr), temp); */
349559014Sroger	OUTB(bktr, BKTR_E_DELAY_LO, temp & 0xff);
349659014Sroger	OUTB(bktr, BKTR_O_DELAY_LO, temp & 0xff);
349759014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xc);
349859014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xc);
349959014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 6) & 0xc));
350059014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 6) & 0xc));
350138706Ssos
350233025Sahasty	/* vertical scale */
350333025Sahasty
350438706Ssos	if (bktr->capture_area_enabled) {
350538706Ssos	  if (bktr->flags  & METEOR_ONLY_ODD_FIELDS ||
350638706Ssos	      bktr->flags & METEOR_ONLY_EVEN_FIELDS)
350738706Ssos	    tmp_int = 65536 -
350838706Ssos	    (((bktr->capture_area_y_size  * 256 + (bktr->rows/2)) / bktr->rows) - 512);
350938706Ssos	  else {
351038706Ssos	    tmp_int = 65536 -
351138706Ssos	    (((bktr->capture_area_y_size * 512 + (bktr->rows / 2)) /  bktr->rows) - 512);
351238706Ssos	  }
351338706Ssos	} else {
351438706Ssos	  if (bktr->flags  & METEOR_ONLY_ODD_FIELDS ||
351538706Ssos	      bktr->flags & METEOR_ONLY_EVEN_FIELDS)
351638706Ssos	    tmp_int = 65536 -
351733025Sahasty	    (((fp->vactive  * 256 + (bktr->rows/2)) / bktr->rows) - 512);
351838706Ssos	  else {
351938706Ssos	    tmp_int = 65536  -
352033025Sahasty	    (((fp->vactive * 512 + (bktr->rows / 2)) /  bktr->rows) - 512);
352138706Ssos	  }
352233025Sahasty	}
352338706Ssos
352433025Sahasty	tmp_int &= 0x1fff;
352562112Sroger	/* printf("%s: VSCALE value is %d\n", bktr_name(bktr), tmp_int); */
352659014Sroger	OUTB(bktr, BKTR_E_VSCALE_LO, tmp_int & 0xff);
352759014Sroger	OUTB(bktr, BKTR_O_VSCALE_LO, tmp_int & 0xff);
352859014Sroger	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x1f);
352959014Sroger	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x1f);
353059014Sroger	OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | ((tmp_int >> 8) & 0x1f));
353159014Sroger	OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | ((tmp_int >> 8) & 0x1f));
353233025Sahasty
353359014Sroger
353433025Sahasty	/* vertical active */
353538706Ssos	if (bktr->capture_area_enabled)
353638706Ssos	  temp = bktr->capture_area_y_size;
353738706Ssos	else
353838706Ssos	  temp = fp->vactive;
353962112Sroger	/* printf("%s: VACTIVE is %d\n", bktr_name(bktr), temp); */
354059014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x30);
354159014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 4) & 0x30));
354259014Sroger	OUTB(bktr, BKTR_E_VACTIVE_LO, temp & 0xff);
354359014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x30);
354459014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 4) & 0x30));
354559014Sroger	OUTB(bktr, BKTR_O_VACTIVE_LO, temp & 0xff);
354638706Ssos
354733025Sahasty	/* vertical delay */
354838706Ssos	if (bktr->capture_area_enabled)
354938706Ssos	  temp = fp->vdelay + (bktr->capture_area_y_offset);
355038706Ssos	else
355138706Ssos	  temp = fp->vdelay;
355262112Sroger	/* printf("%s: VDELAY is %d\n", bktr_name(bktr), temp); */
355359014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xC0);
355459014Sroger	OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 2) & 0xC0));
355559014Sroger	OUTB(bktr, BKTR_E_VDELAY_LO, temp & 0xff);
355659014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xC0);
355759014Sroger	OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 2) & 0xC0));
355859014Sroger	OUTB(bktr, BKTR_O_VDELAY_LO, temp & 0xff);
355933025Sahasty
356033025Sahasty	/* end of video params */
356133025Sahasty
356239842Ssos	if ((bktr->xtal_pll_mode == BT848_USE_PLL)
356339842Ssos	   && (fp->iform_xtsel==BT848_IFORM_X_XT1)) {
356459014Sroger		OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_PLL); /* Select PLL mode */
356538707Ssos	} else {
356659014Sroger		OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_XTAL); /* Select Normal xtal 0/xtal 1 mode */
356738707Ssos	}
356838707Ssos
356924087Sfsmp	/* capture control */
357024087Sfsmp	switch (i_flag) {
357124087Sfsmp	case 1:
357225329Sfsmp	        bktr->bktr_cap_ctl =
357325329Sfsmp		    (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_EVEN);
357459014Sroger		OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20);
357559014Sroger		OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20);
357624087Sfsmp		interlace = 1;
357724087Sfsmp		break;
357824087Sfsmp	 case 2:
357925329Sfsmp 	        bktr->bktr_cap_ctl =
358024528Sfsmp			(BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_ODD);
358159014Sroger		OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20);
358259014Sroger		OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20);
358324087Sfsmp		interlace = 1;
358424087Sfsmp		break;
358524087Sfsmp	 default:
358625329Sfsmp 	        bktr->bktr_cap_ctl =
358724528Sfsmp			(BT848_CAP_CTL_DITH_FRAME |
358824528Sfsmp			 BT848_CAP_CTL_EVEN | BT848_CAP_CTL_ODD);
358959014Sroger		OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x20);
359059014Sroger		OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x20);
359124087Sfsmp		interlace = 2;
359224087Sfsmp		break;
359324087Sfsmp	}
359424087Sfsmp
359559014Sroger	OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
359624087Sfsmp
359724087Sfsmp	rows = bktr->rows;
359824087Sfsmp	cols = bktr->cols;
359924087Sfsmp
360054314Sroger	bktr->vbiflags &= ~VBI_CAPTURE;	/* default - no vbi capture */
360154314Sroger
360259014Sroger	/* RGB Grabs. If /dev/vbi is already open, or we are a PAL/SECAM */
360359014Sroger	/* user, then use the rgb_vbi RISC program. */
360459014Sroger	/* Otherwise, use the normal rgb RISC program */
360559014Sroger	if (pf_int->public.type == METEOR_PIXTYPE_RGB) {
360659014Sroger		if ( (bktr->vbiflags & VBI_OPEN)
360759014Sroger		   ||(bktr->format_params == BT848_IFORM_F_PALBDGHI)
360859014Sroger		   ||(bktr->format_params == BT848_IFORM_F_SECAM)
360959014Sroger                   ){
361059014Sroger			bktr->bktr_cap_ctl |=
361154314Sroger		                BT848_CAP_CTL_VBI_EVEN | BT848_CAP_CTL_VBI_ODD;
361259014Sroger			bktr->vbiflags |= VBI_CAPTURE;
361359014Sroger			rgb_vbi_prog(bktr, i_flag, cols, rows, interlace);
361459014Sroger			return;
361559014Sroger		} else {
361659014Sroger			rgb_prog(bktr, i_flag, cols, rows, interlace);
361759014Sroger			return;
361859014Sroger		}
361947439Sroger	}
362047439Sroger
362129233Smarkm	if ( pf_int->public.type  == METEOR_PIXTYPE_YUV ) {
362224087Sfsmp		yuv422_prog(bktr, i_flag, cols, rows, interlace);
362359014Sroger		OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
362459014Sroger		     | pixfmt_swap_flags( bktr->pixfmt ));
362524087Sfsmp		return;
362624087Sfsmp	}
362724087Sfsmp
362829233Smarkm	if ( pf_int->public.type  == METEOR_PIXTYPE_YUV_PACKED ) {
362924087Sfsmp		yuvpack_prog(bktr, i_flag, cols, rows, interlace);
363059014Sroger		OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
363159014Sroger		     | pixfmt_swap_flags( bktr->pixfmt ));
363224087Sfsmp		return;
363324087Sfsmp	}
363424087Sfsmp
363531186Sahasty	if ( pf_int->public.type  == METEOR_PIXTYPE_YUV_12 ) {
363631186Sahasty		yuv12_prog(bktr, i_flag, cols, rows, interlace);
363759014Sroger		OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
363859014Sroger		     | pixfmt_swap_flags( bktr->pixfmt ));
363931186Sahasty		return;
364031186Sahasty	}
364124087Sfsmp	return;
364224087Sfsmp}
364324087Sfsmp
364424087Sfsmp
364524087Sfsmp/******************************************************************************
364624087Sfsmp * video & video capture specific routines:
364724087Sfsmp */
364824087Sfsmp
364924087Sfsmp
365024087Sfsmp/*
365124087Sfsmp *
365224087Sfsmp */
365324087Sfsmpstatic void
365424528Sfsmpstart_capture( bktr_ptr_t bktr, unsigned type )
365524087Sfsmp{
365624246Sfsmp	u_char			i_flag;
365730980Smarkm	struct format_params   *fp;
365824087Sfsmp
365930980Smarkm	fp = &format_params[bktr->format_params];
366030980Smarkm
366136090Sahasty	/*  If requested, clear out capture buf first  */
366236090Sahasty	if (bktr->clr_on_start && (bktr->video.addr == 0)) {
366336090Sahasty		bzero((caddr_t)bktr->bigbuf,
366436090Sahasty		      (size_t)bktr->rows * bktr->cols * bktr->frames *
366536090Sahasty			pixfmt_table[ bktr->pixfmt ].public.Bpp);
366636090Sahasty	}
366736090Sahasty
366859014Sroger	OUTB(bktr, BKTR_DSTATUS,  0);
366959014Sroger	OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
367024087Sfsmp
367124087Sfsmp	bktr->flags |= type;
367230980Smarkm	bktr->flags &= ~METEOR_WANT_MASK;
367324087Sfsmp	switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
367424087Sfsmp	case METEOR_ONLY_EVEN_FIELDS:
367524087Sfsmp		bktr->flags |= METEOR_WANT_EVEN;
367624087Sfsmp		i_flag = 1;
367724087Sfsmp		break;
367824087Sfsmp	case METEOR_ONLY_ODD_FIELDS:
367924087Sfsmp		bktr->flags |= METEOR_WANT_ODD;
368024087Sfsmp		i_flag = 2;
368124087Sfsmp		break;
368224087Sfsmp	default:
368324087Sfsmp		bktr->flags |= METEOR_WANT_MASK;
368424087Sfsmp		i_flag = 3;
368524087Sfsmp		break;
368624087Sfsmp	}
368724087Sfsmp
368830980Smarkm	/*  TDEC is only valid for continuous captures  */
368930980Smarkm	if ( type == METEOR_SINGLE ) {
369030980Smarkm		u_short	fps_save = bktr->fps;
369130980Smarkm
369230980Smarkm		set_fps(bktr, fp->frame_rate);
369330980Smarkm		bktr->fps = fps_save;
369430980Smarkm	}
369530980Smarkm	else
369630980Smarkm		set_fps(bktr, bktr->fps);
369730980Smarkm
369824528Sfsmp	if (bktr->dma_prog_loaded == FALSE) {
369924087Sfsmp		build_dma_prog(bktr, i_flag);
370024528Sfsmp		bktr->dma_prog_loaded = TRUE;
370124087Sfsmp	}
370224087Sfsmp
370324087Sfsmp
370459014Sroger	OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
370524087Sfsmp
370624087Sfsmp}
370724087Sfsmp
370824528Sfsmp
370924087Sfsmp/*
371024087Sfsmp *
371124087Sfsmp */
371224087Sfsmpstatic void
371324528Sfsmpset_fps( bktr_ptr_t bktr, u_short fps )
371424087Sfsmp{
371529233Smarkm	struct format_params	*fp;
371629233Smarkm	int i_flag;
371724087Sfsmp
371829233Smarkm	fp = &format_params[bktr->format_params];
371929233Smarkm
372029233Smarkm	switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
372129233Smarkm	case METEOR_ONLY_EVEN_FIELDS:
372229233Smarkm		bktr->flags |= METEOR_WANT_EVEN;
372329233Smarkm		i_flag = 1;
372429233Smarkm		break;
372529233Smarkm	case METEOR_ONLY_ODD_FIELDS:
372629233Smarkm		bktr->flags |= METEOR_WANT_ODD;
372729233Smarkm		i_flag = 1;
372829233Smarkm		break;
372929233Smarkm	default:
373029233Smarkm		bktr->flags |= METEOR_WANT_MASK;
373129233Smarkm		i_flag = 2;
373229233Smarkm		break;
373329233Smarkm	}
373429233Smarkm
373559014Sroger	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
373659014Sroger	OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
373724087Sfsmp
373824087Sfsmp	bktr->fps = fps;
373959014Sroger	OUTB(bktr, BKTR_TDEC, 0);
374024087Sfsmp
374129233Smarkm	if (fps < fp->frame_rate)
374259014Sroger		OUTB(bktr, BKTR_TDEC, i_flag*(fp->frame_rate - fps) & 0x3f);
374330980Smarkm	else
374459014Sroger		OUTB(bktr, BKTR_TDEC, 0);
374529233Smarkm	return;
374624087Sfsmp
374724087Sfsmp}
374824087Sfsmp
374924087Sfsmp
375024087Sfsmp
375124087Sfsmp
375224087Sfsmp
375325329Sfsmp/*
375425329Sfsmp * Given a pixfmt index, compute the bt848 swap_flags necessary to
375525329Sfsmp *   achieve the specified swapping.
375625329Sfsmp * Note that without bt swapping, 2Bpp and 3Bpp modes are written
375725329Sfsmp *   byte-swapped, and 4Bpp modes are byte and word swapped (see Table 6
375825329Sfsmp *   and read R->L).
375931186Sahasty * Note also that for 3Bpp, we may additionally need to do some creative
376031186Sahasty *   SKIPing to align the FIFO bytelines with the target buffer (see split()).
376125329Sfsmp * This is abstracted here: e.g. no swaps = RGBA; byte & short swap = ABGR
376225329Sfsmp *   as one would expect.
376325329Sfsmp */
376425329Sfsmp
376525329Sfsmpstatic u_int pixfmt_swap_flags( int pixfmt )
376625329Sfsmp{
376725329Sfsmp	struct meteor_pixfmt *pf = &pixfmt_table[ pixfmt ].public;
376825329Sfsmp	u_int		      swapf = 0;
376925329Sfsmp
377025329Sfsmp	switch ( pf->Bpp ) {
377125329Sfsmp	case 2 : swapf = ( pf->swap_bytes ? 0 : BSWAP );
377225329Sfsmp		 break;
377325329Sfsmp
377425329Sfsmp	case 3 : /* no swaps supported for 3bpp - makes no sense w/ bt848 */
377525329Sfsmp		 break;
377625329Sfsmp
377725329Sfsmp	case 4 : if ( pf->swap_bytes )
377825329Sfsmp			swapf = pf->swap_shorts ? 0 : WSWAP;
377925329Sfsmp		 else
378025329Sfsmp			swapf = pf->swap_shorts ? BSWAP : (BSWAP | WSWAP);
378125329Sfsmp		 break;
378225329Sfsmp	}
378325329Sfsmp	return swapf;
378425329Sfsmp}
378525329Sfsmp
378625329Sfsmp
378725329Sfsmp
378825329Sfsmp/*
378925329Sfsmp * Converts meteor-defined pixel formats (e.g. METEOR_GEO_RGB16) into
379025329Sfsmp *   our pixfmt_table indices.
379125329Sfsmp */
379225329Sfsmp
379325329Sfsmpstatic int oformat_meteor_to_bt( u_long format )
379425329Sfsmp{
379525329Sfsmp	int    i;
379625329Sfsmp        struct meteor_pixfmt *pf1, *pf2;
379725329Sfsmp
379825329Sfsmp	/*  Find format in compatibility table  */
379925329Sfsmp	for ( i = 0; i < METEOR_PIXFMT_TABLE_SIZE; i++ )
380025329Sfsmp		if ( meteor_pixfmt_table[i].meteor_format == format )
380125329Sfsmp			break;
380225329Sfsmp
380325329Sfsmp	if ( i >= METEOR_PIXFMT_TABLE_SIZE )
380425329Sfsmp		return -1;
380525329Sfsmp	pf1 = &meteor_pixfmt_table[i].public;
380625329Sfsmp
380725329Sfsmp	/*  Match it with an entry in master pixel format table  */
380825329Sfsmp	for ( i = 0; i < PIXFMT_TABLE_SIZE; i++ ) {
380925329Sfsmp		pf2 = &pixfmt_table[i].public;
381025329Sfsmp
381125329Sfsmp		if (( pf1->type        == pf2->type        ) &&
381225329Sfsmp		    ( pf1->Bpp         == pf2->Bpp         ) &&
381347380Sbde		    !bcmp( pf1->masks, pf2->masks, sizeof( pf1->masks )) &&
381425329Sfsmp		    ( pf1->swap_bytes  == pf2->swap_bytes  ) &&
381525329Sfsmp		    ( pf1->swap_shorts == pf2->swap_shorts ))
381625329Sfsmp			break;
381725329Sfsmp	}
381825329Sfsmp	if ( i >= PIXFMT_TABLE_SIZE )
381925329Sfsmp		return -1;
382025329Sfsmp
382125329Sfsmp	return i;
382225329Sfsmp}
382325329Sfsmp
382424087Sfsmp/******************************************************************************
382524087Sfsmp * i2c primitives:
382624087Sfsmp */
382724087Sfsmp
382824528Sfsmp/* */
382924528Sfsmp#define I2CBITTIME		(0x5<<4)	/* 5 * 0.48uS */
383037611Sahasty#define I2CBITTIME_878              (1 << 7)
383124246Sfsmp#define I2C_READ		0x01
383224528Sfsmp#define I2C_COMMAND		(I2CBITTIME |			\
383324528Sfsmp				 BT848_DATA_CTL_I2CSCL |	\
383424528Sfsmp				 BT848_DATA_CTL_I2CSDA)
383524246Sfsmp
383637611Sahasty#define I2C_COMMAND_878		(I2CBITTIME_878 |			\
383737611Sahasty				 BT848_DATA_CTL_I2CSCL |	\
383837611Sahasty				 BT848_DATA_CTL_I2CSDA)
383937611Sahasty
384043353Sroger/* Select between old i2c code and new iicbus / smbus code */
384165692Sroger#if defined(BKTR_USE_FREEBSD_SMBUS)
384237611Sahasty
384323599Smarkm/*
384440781Snsouch * The hardware interface is actually SMB commands
384540781Snsouch */
384651694Srogerint
384740781Snsouchi2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 )
384840781Snsouch{
384940781Snsouch	char cmd;
385040781Snsouch
385143770Sroger	if (bktr->id == BROOKTREE_848  ||
385243770Sroger	    bktr->id == BROOKTREE_848A ||
385347491Sroger	    bktr->id == BROOKTREE_849A)
385440781Snsouch		cmd = I2C_COMMAND;
385540781Snsouch	else
385640781Snsouch		cmd = I2C_COMMAND_878;
385740781Snsouch
385840781Snsouch	if (byte2 != -1) {
385940781Snsouch		if (smbus_writew(bktr->i2c_sc.smbus, addr, cmd,
386040781Snsouch			(short)(((byte2 & 0xff) << 8) | (byte1 & 0xff))))
386140781Snsouch			return (-1);
386240781Snsouch	} else {
386340781Snsouch		if (smbus_writeb(bktr->i2c_sc.smbus, addr, cmd,
386440781Snsouch			(char)(byte1 & 0xff)))
386540781Snsouch			return (-1);
386640781Snsouch	}
386740781Snsouch
386840781Snsouch	/* return OK */
386940781Snsouch	return( 0 );
387040781Snsouch}
387140781Snsouch
387251694Srogerint
387340781Snsouchi2cRead( bktr_ptr_t bktr, int addr )
387440781Snsouch{
387540781Snsouch	char result;
387640781Snsouch	char cmd;
387740781Snsouch
387843770Sroger	if (bktr->id == BROOKTREE_848  ||
387943770Sroger	    bktr->id == BROOKTREE_848A ||
388047491Sroger	    bktr->id == BROOKTREE_849A)
388140781Snsouch		cmd = I2C_COMMAND;
388240781Snsouch	else
388340781Snsouch		cmd = I2C_COMMAND_878;
388440781Snsouch
388540781Snsouch	if (smbus_readb(bktr->i2c_sc.smbus, addr, cmd, &result))
388640781Snsouch		return (-1);
388740781Snsouch
388843099Sroger	return ((int)((unsigned char)result));
388940781Snsouch}
389040781Snsouch
3891129755Sjosef#define IICBUS(bktr) ((bktr)->i2c_sc.iicbb)
389243353Sroger
389352593Sroger/* The MSP34xx and DPL35xx Audio chip require i2c bus writes of up */
389452593Sroger/* to 5 bytes which the bt848 automated i2c bus controller cannot handle */
389543353Sroger/* Therefore we need low level control of the i2c bus hardware */
389643353Sroger
389752593Sroger/* Write to the MSP or DPL registers */
389851694Srogervoid
389952593Srogermsp_dpl_write(bktr_ptr_t bktr, int i2c_addr,  unsigned char dev, unsigned int addr, unsigned int data)
390043353Sroger{
390143353Sroger	unsigned char addr_l, addr_h, data_h, data_l ;
390243353Sroger
390343353Sroger	addr_h = (addr >>8) & 0xff;
390443353Sroger	addr_l = addr & 0xff;
390543353Sroger	data_h = (data >>8) & 0xff;
390643353Sroger	data_l = data & 0xff;
390743353Sroger
390852593Sroger	iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
390943353Sroger
391043353Sroger	iicbus_write_byte(IICBUS(bktr), dev, 0);
391143353Sroger	iicbus_write_byte(IICBUS(bktr), addr_h, 0);
391243353Sroger	iicbus_write_byte(IICBUS(bktr), addr_l, 0);
391343353Sroger	iicbus_write_byte(IICBUS(bktr), data_h, 0);
391443353Sroger	iicbus_write_byte(IICBUS(bktr), data_l, 0);
391543353Sroger
391643353Sroger	iicbus_stop(IICBUS(bktr));
391743353Sroger
391843353Sroger	return;
391943353Sroger}
392043353Sroger
392152593Sroger/* Read from the MSP or DPL registers */
392251694Srogerunsigned int
392352593Srogermsp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr)
392443353Sroger{
392543353Sroger	unsigned int data;
392643353Sroger	unsigned char addr_l, addr_h, dev_r;
392743353Sroger	int read;
392843353Sroger	u_char data_read[2];
392943353Sroger
393043353Sroger	addr_h = (addr >>8) & 0xff;
393143353Sroger	addr_l = addr & 0xff;
393243353Sroger	dev_r = dev+1;
393343353Sroger
393443353Sroger	/* XXX errors ignored */
393552593Sroger	iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
393643353Sroger
393743353Sroger	iicbus_write_byte(IICBUS(bktr), dev_r, 0);
393843353Sroger	iicbus_write_byte(IICBUS(bktr), addr_h, 0);
393943353Sroger	iicbus_write_byte(IICBUS(bktr), addr_l, 0);
394043353Sroger
394152593Sroger	iicbus_repeated_start(IICBUS(bktr), i2c_addr +1, 0 /* no timeout? */);
394243353Sroger	iicbus_read(IICBUS(bktr), data_read, 2, &read, IIC_LAST_READ, 0);
394343353Sroger	iicbus_stop(IICBUS(bktr));
394443353Sroger
394543353Sroger	data = (data_read[0]<<8) | data_read[1];
394643353Sroger
394743353Sroger	return (data);
394843353Sroger}
394943353Sroger
395052593Sroger/* Reset the MSP or DPL chip */
395146164Sroger/* The user can block the reset (which is handy if you initialise the
395252593Sroger * MSP and/or DPL audio in another operating system first (eg in Windows)
395346164Sroger */
395451694Srogervoid
395552593Srogermsp_dpl_reset( bktr_ptr_t bktr, int i2c_addr )
395643353Sroger{
395746164Sroger
395846164Sroger#ifndef BKTR_NO_MSP_RESET
395943353Sroger	/* put into reset mode */
396052593Sroger	iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
396143353Sroger	iicbus_write_byte(IICBUS(bktr), 0x00, 0);
396243353Sroger	iicbus_write_byte(IICBUS(bktr), 0x80, 0);
396343353Sroger	iicbus_write_byte(IICBUS(bktr), 0x00, 0);
396443353Sroger	iicbus_stop(IICBUS(bktr));
396543353Sroger
396643353Sroger	/* put back to operational mode */
396752593Sroger	iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
396843353Sroger	iicbus_write_byte(IICBUS(bktr), 0x00, 0);
396943353Sroger	iicbus_write_byte(IICBUS(bktr), 0x00, 0);
397043353Sroger	iicbus_write_byte(IICBUS(bktr), 0x00, 0);
397143353Sroger	iicbus_stop(IICBUS(bktr));
397246164Sroger#endif
397343353Sroger	return;
397443353Sroger}
397543353Sroger
397643890Srogerstatic void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) {
397743890Sroger	int read;
397843890Sroger
397943890Sroger	/* XXX errors ignored */
398043890Sroger	iicbus_start(IICBUS(bktr), bktr->remote_control_addr, 0 /* no timeout? */);
398143890Sroger	iicbus_read(IICBUS(bktr),  remote->data, 3, &read, IIC_LAST_READ, 0);
398243890Sroger	iicbus_stop(IICBUS(bktr));
398343890Sroger
398443890Sroger	return;
398543890Sroger}
398643890Sroger
398765692Sroger#else /* defined(BKTR_USE_FREEBSD_SMBUS) */
398840781Snsouch
398940781Snsouch/*
399043353Sroger * Program the i2c bus directly
399123599Smarkm */
399251694Srogerint
399324528Sfsmpi2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 )
399423599Smarkm{
399524246Sfsmp	u_long		x;
399624246Sfsmp	u_long		data;
399723599Smarkm
399824246Sfsmp	/* clear status bits */
399959014Sroger	OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE);
400023599Smarkm
400124246Sfsmp	/* build the command datum */
400243770Sroger	if (bktr->id == BROOKTREE_848  ||
400343770Sroger	    bktr->id == BROOKTREE_848A ||
400447491Sroger	    bktr->id == BROOKTREE_849A) {
400537611Sahasty	  data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND;
400637611Sahasty	} else {
400737611Sahasty	  data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND_878;
400837611Sahasty	}
400924246Sfsmp	if ( byte2 != -1 ) {
401024246Sfsmp		data |= ((byte2 & 0xff) << 8);
401124528Sfsmp		data |= BT848_DATA_CTL_I2CW3B;
401224246Sfsmp	}
401324246Sfsmp
401424246Sfsmp	/* write the address and data */
401559014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, data);
401624246Sfsmp
401724246Sfsmp	/* wait for completion */
401824528Sfsmp	for ( x = 0x7fffffff; x; --x ) {	/* safety valve */
401959014Sroger		if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE )
402024246Sfsmp			break;
402124246Sfsmp	}
402224246Sfsmp
402324246Sfsmp	/* check for ACK */
402459014Sroger	if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) )
402524528Sfsmp		return( -1 );
402624246Sfsmp
402724246Sfsmp	/* return OK */
402824528Sfsmp	return( 0 );
402923599Smarkm}
403023599Smarkm
403123599Smarkm
403223599Smarkm/*
403324246Sfsmp *
403423599Smarkm */
403551694Srogerint
403624528Sfsmpi2cRead( bktr_ptr_t bktr, int addr )
403723599Smarkm{
403824246Sfsmp	u_long		x;
403924046Sfsmp
404024246Sfsmp	/* clear status bits */
404159014Sroger	OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE);
404223599Smarkm
404324246Sfsmp	/* write the READ address */
404437611Sahasty	/* The Bt878 and Bt879  differed on the treatment of i2c commands */
404537611Sahasty
404643770Sroger	if (bktr->id == BROOKTREE_848  ||
404743770Sroger	    bktr->id == BROOKTREE_848A ||
404847491Sroger	    bktr->id == BROOKTREE_849A) {
404959014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND);
405037611Sahasty	} else {
405159014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND_878);
405237611Sahasty	}
405323599Smarkm
405424246Sfsmp	/* wait for completion */
405524528Sfsmp	for ( x = 0x7fffffff; x; --x ) {	/* safety valve */
405659014Sroger		if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE )
405724246Sfsmp			break;
405824246Sfsmp	}
405923599Smarkm
406024246Sfsmp	/* check for ACK */
406159014Sroger	if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) )
406224528Sfsmp		return( -1 );
406324246Sfsmp
406424246Sfsmp	/* it was a read */
406559014Sroger	return( (INL(bktr, BKTR_I2C_DATA_CTL) >> 8) & 0xff );
406623599Smarkm}
406723599Smarkm
406843353Sroger/* The MSP34xx Audio chip require i2c bus writes of up to 5 bytes which the */
406943353Sroger/* bt848 automated i2c bus controller cannot handle */
407043353Sroger/* Therefore we need low level control of the i2c bus hardware */
407143353Sroger/* Idea for the following functions are from elsewhere in this driver and */
407243353Sroger/* from the Linux BTTV i2c driver by Gerd Knorr <kraxel@cs.tu-berlin.de> */
407343353Sroger
407443353Sroger#define BITD    40
407543353Srogerstatic void i2c_start( bktr_ptr_t bktr) {
407659014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release data */
407759014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release clock */
407859014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* lower data */
407959014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock */
408043353Sroger}
408143353Sroger
408243353Srogerstatic void i2c_stop( bktr_ptr_t bktr) {
408359014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock & data */
408459014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* release clock */
408559014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release data */
408643353Sroger}
408743353Sroger
408843353Srogerstatic int i2c_write_byte( bktr_ptr_t bktr, unsigned char data) {
408943353Sroger        int x;
409043353Sroger        int status;
409143353Sroger
409243353Sroger        /* write out the byte */
409343353Sroger        for ( x = 7; x >= 0; --x ) {
409443353Sroger                if ( data & (1<<x) ) {
409559014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
409643353Sroger                        DELAY( BITD );          /* assert HI data */
409759014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
409843353Sroger                        DELAY( BITD );          /* strobe clock */
409959014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
410043353Sroger                        DELAY( BITD );          /* release clock */
410143353Sroger                }
410243353Sroger                else {
410359014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
410443353Sroger                        DELAY( BITD );          /* assert LO data */
410559014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
410643353Sroger                        DELAY( BITD );          /* strobe clock */
410759014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
410843353Sroger                        DELAY( BITD );          /* release clock */
410943353Sroger                }
411043353Sroger        }
411143353Sroger
411243353Sroger        /* look for an ACK */
411359014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* float data */
411459014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* strobe clock */
411559014Sroger        status = INL(bktr, BKTR_I2C_DATA_CTL) & 1;       /* read the ACK bit */
411659014Sroger        OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release clock */
411743353Sroger
411843353Sroger        return( status );
411943353Sroger}
412043353Sroger
412143353Srogerstatic int i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last ) {
412243353Sroger        int x;
412343353Sroger        int bit;
412443353Sroger        int byte = 0;
412543353Sroger
412643353Sroger        /* read in the byte */
412759014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
412843353Sroger        DELAY( BITD );                          /* float data */
412943353Sroger        for ( x = 7; x >= 0; --x ) {
413059014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
413143353Sroger                DELAY( BITD );                  /* strobe clock */
413259014Sroger                bit = INL(bktr, BKTR_I2C_DATA_CTL) & 1;  /* read the data bit */
413343353Sroger                if ( bit ) byte |= (1<<x);
413459014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
413543353Sroger                DELAY( BITD );                  /* release clock */
413643353Sroger        }
413743353Sroger        /* After reading the byte, send an ACK */
413843353Sroger        /* (unless that was the last byte, for which we send a NAK */
413943353Sroger        if (last) { /* send NAK - same a writing a 1 */
414059014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
414143353Sroger                DELAY( BITD );                  /* set data bit */
414259014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
414343353Sroger                DELAY( BITD );                  /* strobe clock */
414459014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
414543353Sroger                DELAY( BITD );                  /* release clock */
414643353Sroger        } else { /* send ACK - same as writing a 0 */
414759014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
414843353Sroger                DELAY( BITD );                  /* set data bit */
414959014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
415043353Sroger                DELAY( BITD );                  /* strobe clock */
415159014Sroger		OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
415243353Sroger                DELAY( BITD );                  /* release clock */
415343353Sroger        }
415443353Sroger
415543353Sroger        *data=byte;
415643353Sroger	return 0;
415743353Sroger}
415843353Sroger#undef BITD
415943353Sroger
416052593Sroger/* Write to the MSP or DPL registers */
416152593Srogervoid msp_dpl_write( bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr,
416252593Sroger		    unsigned int data){
416352593Sroger	unsigned int msp_w_addr = i2c_addr;
416443353Sroger	unsigned char addr_l, addr_h, data_h, data_l ;
416543353Sroger	addr_h = (addr >>8) & 0xff;
416643353Sroger	addr_l = addr & 0xff;
416743353Sroger	data_h = (data >>8) & 0xff;
416843353Sroger	data_l = data & 0xff;
416943353Sroger
417043353Sroger	i2c_start(bktr);
417143353Sroger	i2c_write_byte(bktr, msp_w_addr);
417243353Sroger	i2c_write_byte(bktr, dev);
417343353Sroger	i2c_write_byte(bktr, addr_h);
417443353Sroger	i2c_write_byte(bktr, addr_l);
417543353Sroger	i2c_write_byte(bktr, data_h);
417643353Sroger	i2c_write_byte(bktr, data_l);
417743353Sroger	i2c_stop(bktr);
417843353Sroger}
417943353Sroger
418052593Sroger/* Read from the MSP or DPL registers */
418152593Srogerunsigned int msp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr){
418243353Sroger	unsigned int data;
418343353Sroger	unsigned char addr_l, addr_h, data_1, data_2, dev_r ;
418443353Sroger	addr_h = (addr >>8) & 0xff;
418543353Sroger	addr_l = addr & 0xff;
418643353Sroger	dev_r = dev+1;
418743353Sroger
418843353Sroger	i2c_start(bktr);
418952593Sroger	i2c_write_byte(bktr,i2c_addr);
419043353Sroger	i2c_write_byte(bktr,dev_r);
419143353Sroger	i2c_write_byte(bktr,addr_h);
419243353Sroger	i2c_write_byte(bktr,addr_l);
419343353Sroger
419443353Sroger	i2c_start(bktr);
419552593Sroger	i2c_write_byte(bktr,i2c_addr+1);
419643353Sroger	i2c_read_byte(bktr,&data_1, 0);
419743353Sroger	i2c_read_byte(bktr,&data_2, 1);
419843353Sroger	i2c_stop(bktr);
419943353Sroger	data = (data_1<<8) | data_2;
420043353Sroger	return data;
420143353Sroger}
420243353Sroger
420352593Sroger/* Reset the MSP or DPL chip */
420446164Sroger/* The user can block the reset (which is handy if you initialise the
420546164Sroger * MSP audio in another operating system first (eg in Windows)
420646164Sroger */
420752593Srogervoid msp_dpl_reset( bktr_ptr_t bktr, int i2c_addr ) {
420843353Sroger
420946164Sroger#ifndef BKTR_NO_MSP_RESET
421043353Sroger	/* put into reset mode */
421143353Sroger	i2c_start(bktr);
421252593Sroger	i2c_write_byte(bktr, i2c_addr);
421343353Sroger	i2c_write_byte(bktr, 0x00);
421443353Sroger	i2c_write_byte(bktr, 0x80);
421543353Sroger	i2c_write_byte(bktr, 0x00);
421643353Sroger	i2c_stop(bktr);
421743353Sroger
421843353Sroger	/* put back to operational mode */
421943353Sroger	i2c_start(bktr);
422052593Sroger	i2c_write_byte(bktr, i2c_addr);
422143353Sroger	i2c_write_byte(bktr, 0x00);
422243353Sroger	i2c_write_byte(bktr, 0x00);
422343353Sroger	i2c_write_byte(bktr, 0x00);
422443353Sroger	i2c_stop(bktr);
422546164Sroger#endif
422646164Sroger	return;
422743353Sroger
422843353Sroger}
422943353Sroger
423043890Srogerstatic void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) {
423143890Sroger
423243890Sroger	/* XXX errors ignored */
423343890Sroger	i2c_start(bktr);
423443890Sroger	i2c_write_byte(bktr,bktr->remote_control_addr);
423543890Sroger	i2c_read_byte(bktr,&(remote->data[0]), 0);
423643890Sroger	i2c_read_byte(bktr,&(remote->data[1]), 0);
423743890Sroger	i2c_read_byte(bktr,&(remote->data[2]), 0);
423843890Sroger	i2c_stop(bktr);
423943890Sroger
424043890Sroger	return;
424143890Sroger}
424243890Sroger
424365692Sroger#endif /* defined(BKTR_USE_FREEBSD_SMBUS) */
424443890Sroger
424540781Snsouch
424624246Sfsmp#if defined( I2C_SOFTWARE_PROBE )
424724246Sfsmp
424823599Smarkm/*
424924246Sfsmp * we are keeping this around for any parts that we need to probe
425024246Sfsmp * but that CANNOT be probed via an i2c read.
425124246Sfsmp * this is necessary because the hardware i2c mechanism
425224246Sfsmp * cannot be programmed for 1 byte writes.
425324246Sfsmp * currently there are no known i2c parts that we need to probe
425424246Sfsmp * and that cannot be safely read.
425523599Smarkm */
425624528Sfsmpstatic int	i2cProbe( bktr_ptr_t bktr, int addr );
425724528Sfsmp#define BITD		40
425824246Sfsmp#define EXTRA_START
425923599Smarkm
426023599Smarkm/*
426124246Sfsmp * probe for an I2C device at addr.
426223599Smarkm */
426323599Smarkmstatic int
426424528Sfsmpi2cProbe( bktr_ptr_t bktr, int addr )
426523599Smarkm{
426624528Sfsmp	int		x, status;
426723599Smarkm
426824246Sfsmp	/* the START */
426924246Sfsmp#if defined( EXTRA_START )
427059014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD );	/* release data */
427159014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD );	/* release clock */
427224246Sfsmp#endif /* EXTRA_START */
427359014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD );	/* lower data */
427459014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD );	/* lower clock */
427523599Smarkm
427624246Sfsmp	/* write addr */
427724246Sfsmp	for ( x = 7; x >= 0; --x ) {
427824246Sfsmp		if ( addr & (1<<x) ) {
427959014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
428024528Sfsmp			DELAY( BITD );		/* assert HI data */
428159014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
428224528Sfsmp			DELAY( BITD );		/* strobe clock */
428359014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
428424528Sfsmp			DELAY( BITD );		/* release clock */
428524246Sfsmp		}
428624246Sfsmp		else {
428762112Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
428824528Sfsmp			DELAY( BITD );		/* assert LO data */
428959014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
429024528Sfsmp			DELAY( BITD );		/* strobe clock */
429159014Sroger			OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
429224528Sfsmp			DELAY( BITD );		/* release clock */
429324246Sfsmp		}
429424246Sfsmp	}
429523599Smarkm
429624246Sfsmp	/* look for an ACK */
429759014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD );	/* float data */
429859014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD );	/* strobe clock */
429959014Sroger	status = INL(bktr, BKTR_I2C_DATA_CTL) & 1;	/* read the ACK bit */
430059014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD );	/* release clock */
430123599Smarkm
430224246Sfsmp	/* the STOP */
430359014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD );	/* lower clock & data */
430459014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD );	/* release clock */
430559014Sroger	OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD );	/* release data */
430624246Sfsmp
430724528Sfsmp	return( status );
430823599Smarkm}
430924246Sfsmp#undef EXTRA_START
431024528Sfsmp#undef BITD
431123599Smarkm
431224246Sfsmp#endif /* I2C_SOFTWARE_PROBE */
431323599Smarkm
431423599Smarkm
431540781Snsouch#define ABSENT		(-1)
431640781Snsouch
431750693Sroger#endif /* FreeBSD, BSDI, NetBSD, OpenBSD */
431848781Sroger
4319