diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1998-07-23 08:38:29 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1998-07-23 08:38:29 +0000 |
commit | 241094e974354366bc832c66d96b7c140d9ff96b (patch) | |
tree | 9989e160a4705a9122cd9a7b185e242b1c2cb53a /sys/dev | |
parent | 562c559a05036fb0151a45dc276ab9132e43e7a1 (diff) |
brooktree driver, hacked by matthieu. This needs cleaning now that it is in the tree
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/brktree_reg.h | 481 | ||||
-rw-r--r-- | sys/dev/pci/brooktree848.c | 5378 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 7 |
3 files changed, 5865 insertions, 1 deletions
diff --git a/sys/dev/pci/brktree_reg.h b/sys/dev/pci/brktree_reg.h new file mode 100644 index 00000000000..ee2f26da800 --- /dev/null +++ b/sys/dev/pci/brktree_reg.h @@ -0,0 +1,481 @@ +/* + * Copyright (c) 1995 Mark Tinguely and Jim Lowe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Tinguely and Jim Lowe + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PCI_LATENCY_TIMER +#define PCI_LATENCY_TIMER 0x0c /* pci timer register */ +#endif + +/* + * Definitions for the Philips SAA7116 digital video to pci interface. + */ +#define BROOKTREE_848_ID 0x0350109E +#define BROOKTREE 849_ID 0x0351109E + +typedef volatile u_int bregister_t; +/* + * if other persuasion endian, then compiler will probably require that + * these next + * macros be reversed + */ +#define BTBYTE(what) bregister_t what:8; int :24 +#define BTWORD(what) bregister_t what:16; int: 16 +#define BTLONG(what) bregister_t what:32 + +struct bt848_registers { + BTBYTE (dstatus); /* 0, 1,2,3 */ +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + BTBYTE (iform); /* 4, 5,6,7 */ +#define BT848_IFORM_MUXSEL (0x3<<5) +# define BT848_IFORM_M_MUX1 (0x03<<5) +# define BT848_IFORM_M_MUX0 (0x02<<5) +# define BT848_IFORM_M_MUX2 (0x01<<5) +# define BT848_IFORM_M_RSVD (0x00<<5) +#define BT848_IFORM_XTSEL (0x3<<3) +# define BT848_IFORM_X_AUTO (0x03<<3) +# define BT848_IFORM_X_XT1 (0x02<<3) +# define BT848_IFORM_X_XT0 (0x01<<3) +# define BT848_IFORM_X_RSVD (0x00<<3) + BTBYTE (tdec); /* 8, 9,a,b */ + BTBYTE (e_crop); /* c, d,e,f */ + BTBYTE (e_vdelay_lo); /* 10, 11,12,13 */ + BTBYTE (e_vactive_lo); /* 14, 15,16,17 */ + BTBYTE (e_delay_lo); /* 18, 19,1a,1b */ + BTBYTE (e_hactive_lo); /* 1c, 1d,1e,1f */ + BTBYTE (e_hscale_hi); /* 20, 21,22,23 */ + BTBYTE (e_hscale_lo); /* 24, 25,26,27 */ + BTBYTE (bright); /* 28, 29,2a,2b */ + BTBYTE (e_control); /* 2c, 2d,2e,2f */ +#define BT848_E_CONTROL_LNOTCH (1<<7) +#define BT848_E_CONTROL_COMP (1<<6) +#define BT848_E_CONTROL_LDEC (1<<5) +#define BT848_E_CONTROL_CBSENSE (1<<4) +#define BT848_E_CONTROL_RSVD (1<<3) +#define BT848_E_CONTROL_CON_MSB (1<<2) +#define BT848_E_CONTROL_SAT_U_MSB (1<<1) +#define BT848_E_CONTROL_SAT_V_MSB (1<<0) + BTBYTE (contrast_lo); /* 30, 31,32,33 */ + BTBYTE (sat_u_lo); /* 34, 35,36,37 */ + BTBYTE (sat_v_lo); /* 38, 39,3a,3b */ + BTBYTE (hue); /* 3c, 3d,3e,3f */ + BTBYTE (e_scloop); /* 40, 41,42,43 */ +#define BT848_E_SCLOOP_RSVD1 (1<<7) +#define BT848_E_SCLOOP_CAGC (1<<6) +#define BT848_E_SCLOOP_CKILL (1<<5) +#define BT848_E_SCLOOP_HFILT (0x3<<3) +# define BT848_E_SCLOOP_HFILT_ICON (0x3<<3) +# define BT848_E_SCLOOP_HFILT_QCIF (0x2<<3) +# define BT848_E_SCLOOP_HFILT_CIF (0x1<<3) +# define BT848_E_SCLOOP_HFILT_AUTO (0x0<<3) +#define BT848_E_SCLOOP_RSVD0 (0x7<<0) + int :32; /* 44, 45,46,47 */ + BTBYTE (oform); /* 48, 49,4a,4b */ + BTBYTE (e_vscale_hi); /* 4c, 4d,4e,4f */ + BTBYTE (e_vscale_lo); /* 50, 51,52,53 */ + BTBYTE (test); /* 54, 55,56,57 */ + int :32; /* 58, 59,5a,5b */ + int :32; /* 5c, 5d,5e,5f */ + BTLONG (adelay); /* 60, 61,62,63 */ + BTBYTE (bdelay); /* 64, 65,66,67 */ + BTBYTE (adc); /* 68, 69,6a,6b */ +#define BT848_ADC_RESERVED (0x80) /* required pattern */ +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + BTBYTE (e_vtc); /* 6c, 6d,6e,6f */ + int :32; /* 70, 71,72,73 */ + int :32; /* 74, 75,76,77 */ + int :32; /* 78, 79,7a,7b */ + BTLONG (sreset); /* 7c, 7d,7e,7f */ + u_char filler[0x8c-0x80]; + BTBYTE (o_crop); /* 8c, 8d,8e,8f */ + BTBYTE (o_vdelay_lo); /* 90, 91,92,93 */ + BTBYTE (o_vactive_lo); /* 94, 95,96,97 */ + BTBYTE (o_delay_lo); /* 98, 99,9a,9b */ + BTBYTE (o_hactive_lo); /* 9c, 9d,9e,9f */ + BTBYTE (o_hscale_hi); /* a0, a1,a2,a3 */ + BTBYTE (o_hscale_lo); /* a4, a5,a6,a7 */ + int :32; /* a8, a9,aa,ab */ + BTBYTE (o_control); /* ac, ad,ae,af */ +#define BT848_O_CONTROL_LNOTCH (1<<7) +#define BT848_O_CONTROL_COMP (1<<6) +#define BT848_O_CONTROL_LDEC (1<<5) +#define BT848_O_CONTROL_CBSENSE (1<<4) +#define BT848_O_CONTROL_RSVD (1<<3) +#define BT848_O_CONTROL_CON_MSB (1<<2) +#define BT848_O_CONTROL_SAT_U_MSB (1<<1) +#define BT848_O_CONTROL_SAT_V_MSB (1<<0) + u_char fillter1[16]; + BTBYTE (o_scloop); /* c0, c1,c2,c3 */ +#define BT848_O_SCLOOP_RSVD1 (1<<7) +#define BT848_O_SCLOOP_CAGC (1<<6) +#define BT848_O_SCLOOP_CKILL (1<<5) +#define BT848_O_SCLOOP_HFILT (0x3<<3) +# define BT848_O_SCLOOP_HFILT_ICON (0x3<<3) +# define BT848_O_SCLOOP_HFILT_QCIF (0x2<<3) +# define BT848_O_SCLOOP_HFILT_CIF (0x1<<3) +# define BT848_O_SCLOOP_HFILT_AUTO (0x0<<3) +#define BT848_O_SCLOOP_RSVD0 (0x7<<0) + int :32; /* c4, c5,c6,c7 */ + int :32; /* c8, c9,ca,cb */ + BTBYTE (o_vscale_hi); /* cc, cd,ce,cf */ + BTBYTE (o_vscale_lo); /* d0, d1,d2,d3 */ + BTBYTE (color_fmt); /* d4, d5,d6,d7 */ + bregister_t color_ctl_swap :4; /* d8 */ +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + bregister_t color_ctl_gamma :1; + bregister_t color_ctl_rgb_ded :1; + bregister_t color_ctl_color_bars :1; + bregister_t color_ctl_ext_frmrate :1; + int :24; /* d9,da,db */ + BTBYTE (cap_ctl); /* dc, dd,de,df */ +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_VBI_ODD (1<<3) +#define BT848_CAP_CTL_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_ODD (1<<1) +#define BT848_CAP_CTL_EVEN (1<<0) + BTBYTE (vbi_pack_size); /* e0, e1,e2,e3 */ + BTBYTE (vbi_pack_del); /* e4, e5,e6,e7 */ + int :32; /* e8, e9,ea,eb */ + BTBYTE (o_vtc); /* ec, ed,ee,ef */ + u_char filler2[0x100-0xf0]; + BTLONG (int_stat); /* 100, 101,102,103 */ + BTLONG (int_mask); /* 104, 105,106,107 */ +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_MYSTERYBIT (1<<23) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_RSV1 (1<<7) +#define BT848_INT_RSV0 (1<<6) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + int :32; /* 108, 109,10a,10b */ + BTWORD (gpio_dma_ctl); /* 10c, 10d,10e,10f */ +#define BT848_DMA_CTL_PL23TP4 (0<<6) /* planar1 trigger 4 */ +#define BT848_DMA_CTL_PL23TP8 (1<<6) /* planar1 trigger 8 */ +#define BT848_DMA_CTL_PL23TP16 (2<<6) /* planar1 trigger 16 */ +#define BT848_DMA_CTL_PL23TP32 (3<<6) /* planar1 trigger 32 */ +#define BT848_DMA_CTL_PL1TP4 (0<<4) /* planar1 trigger 4 */ +#define BT848_DMA_CTL_PL1TP8 (1<<4) /* planar1 trigger 8 */ +#define BT848_DMA_CTL_PL1TP16 (2<<4) /* planar1 trigger 16 */ +#define BT848_DMA_CTL_PL1TP32 (3<<4) /* planar1 trigger 32 */ +#define BT848_DMA_CTL_PKTP4 (0<<2) /* packed trigger 4 */ +#define BT848_DMA_CTL_PKTP8 (1<<2) /* packed trigger 8 */ +#define BT848_DMA_CTL_PKTP16 (2<<2) /* packed trigger 16 */ +#define BT848_DMA_CTL_PKTP32 (3<<2) /* packed trigger 32 */ +#define BT848_DMA_CTL_RISC_EN (1<<1) +#define BT848_DMA_CTL_FIFO_EN (1<<0) + BTLONG (i2c_data_ctl); /* 110, 111,112,113 */ +#define BT848_DATA_CTL_I2CDIV (0xf<<4) +#define BT848_DATA_CTL_I2CSYNC (1<<3) +#define BT848_DATA_CTL_I2CW3B (1<<2) +#define BT848_DATA_CTL_I2CSCL (1<<1) +#define BT848_DATA_CTL_I2CSDA (1<<0) + BTLONG (risc_strt_add); /* 114, 115,116,117 */ + BTLONG (gpio_out_en); /* 118, 119,11a,11b */ /* really 24 bits */ + BTLONG (gpio_reg_inp); /* 11c, 11d,11e,11f */ /* really 24 bits */ + BTLONG (risc_count); /* 120, 121,122,123 */ + u_char filler3[0x200-0x124]; + BTLONG (gpio_data); /* 200, 201,202,203 */ /* really 24 bits */ +}; + +typedef volatile struct bt848_registers* bt848_ptr_t; + + +#if 0 +/* force people to be aware of the new struct */ + +#define BKTR_DSTATUS 0x000 +#define BKTR_IFORM 0x004 +#define BKTR_TDEC 0x008 +#define BKTR_EVEN_CROP 0x00C +#define BKTR_ODD_CROP 0x08C +#define BKTR_E_VDELAY_LO 0x010 +#define BKTR_O_VDELAY_LO 0x090 +#define BKTR_E_VACTIVE_LO 0x014 +#define BKTR_O_VACTIVE_LO 0x094 +#define BKTR_E_DELAY_LO 0x018 +#define BKTR_O_DELAY_LO 0x098 +#define BKTR_E_HACTIVE_LO 0x01C +#define BKTR_O_HACTIVE_LO 0x09C +#define BKTR_E_HSCALE_HI 0x020 +#define BKTR_O_HSCALE_HI 0x0A0 +#define BKTR_E_HSCALE_LO 0x024 +#define BKTR_O_HSCALE_LO 0x0A4 +#define BKTR_BRIGHT 0x028 +#define BKTR_E_CONTROL 0x02C +#define BKTR_O_CONTROL 0x0AC +#define BKTR_CONTRAST_LO 0x030 +#define BKTR_SAT_U_LO 0x034 +#define BKTR_SAT_V_LO 0x038 +#define BKTR_HUE 0x03C +#define BKTR_E_SCLOOP 0x040 +#define BKTR_O_SCLOOP 0x0C0 +#define BKTR_OFORM 0x048 +#define BKTR_E_VSCALE_HI 0x04C +#define BKTR_O_VSCALE_HI 0x0CC +#define BKTR_E_VSCALE_LO 0x050 +#define BKTR_O_VSCALE_LO 0x0D0 +#define BKTR_TEST 0x054 +#define BKTR_ADELAY 0x060 +#define BKTR_BDELAY 0x064 +#define BKTR_ADC 0x068 +#define BKTR_E_VTC 0x06C +#define BKTR_O_VTC 0x0EC +#define BKTR_SRESET 0x07C +#define BKTR_COLOR_FMT 0x0D4 +#define BKTR_COLOR_CTL 0x0D8 +#define BKTR_CAP_CTL 0x0DC +#define BKTR_VBI_PACK_SIZE 0x0E0 +#define BKTR_VBI_PACK_DEL 0x0E4 +#define BKTR_INT_STAT 0x100 +#define BKTR_INT_MASK 0x104 +#define BKTR_RISC_COUNT 0x120 +#define BKTR_RISC_STRT_ADD 0x114 +#define BKTR_GPIO_DMA_CTL 0x10C +#define BKTR_GPIO_OUT_EN 0x118 +#define BKTR_GPIO_REG_INP 0x11C +#define BKTR_GPIO_DATA 0x200 +#define BKTR_I2C_CONTROL 0x110 + +#endif /* 0 */ + +/* + * device support for onboard tv tuners + */ + +/* description of the LOGICAL tuner */ +struct TVTUNER { + int frequency; + u_char chnlset; + u_char channel; + u_char band; + u_char afc; + u_char radio_mode; /* current mode of the radio mode */ +}; + +/* description of the PHYSICAL tuner */ +struct TUNER { + char* name; + u_char type; + u_char pllAddr; + u_char pllControl[4]; + u_char bandLimits[ 2 ]; + u_char bandAddrs[ 4 ]; /* 3 first for the 3 TV + ** bands. Last for radio + ** band (0x00=NoRadio). + */ + +}; + +/* description of the card */ +#define EEPROMBLOCKSIZE 32 +struct CARDTYPE { + char* name; + const struct TUNER* tuner; + u_char dbx; /* Has DBX chip? */ + u_char msp3400c; /* Has msp3400c chip? */ + u_char eepromAddr; + u_char eepromSize; /* bytes / EEPROMBLOCKSIZE */ + u_char audiomuxs[ 5 ]; /* tuner, ext, int/unused, + mute, present */ +}; + +struct format_params { + /* Total lines, lines before image, image lines */ + int vtotal, vdelay, vactive; + /* Total unscaled horizontal pixels, pixels before image, image pixels */ + int htotal, hdelay, hactive; + /* visible active horizontal and vertical : 480 640 for NTSC */ + int horizontal, vertical; +/* frame rate . for ntsc is 30 frames per second */ + int frame_rate; +/* A-delay and B-delay */ + u_char adelay, bdelay; +/* Iform XTSEL value */ + int iform_xtsel; +}; + + +typedef struct bktr_clip bktr_clip_t; +/* + * BrookTree 848 info structure, one per bt848 card installed. + */ +struct bktr_softc { +#ifdef __bsdi__ + struct device bktr_dev; /* base device */ + struct isadev bktr_id; /* ISA device */ + struct intrhand bktr_ih; /* interrupt vectoring */ +#define pcici_t pci_devaddr_t +#endif +#if defined(__NetBSD__) + struct device bktr_dev; /* base device */ + bus_space_tag_t memt; + bus_space_handle_t memh; + bus_size_t obmemsz; /* size of en card (bytes) */ + void *ih; + bus_dmamap_t dm_prog; + bus_dmamap_t dm_oprog; + bus_dmamap_t dm_mem; +#endif +#if defined(__OpenBSD__) + struct device bktr_dev; /* base device */ + bus_dma_tag_t dmat; /* DMA tag */ + bus_space_tag_t memt; + bus_space_handle_t memh; + bus_size_t obmemsz; /* size of en card (bytes) */ + void *ih; + bus_dmamap_t dm_prog; + bus_dmamap_t dm_oprog; + bus_dmamap_t dm_mem; + size_t dm_mapsize; +#endif + bt848_ptr_t base; /* Bt848 register physical address */ + vm_offset_t phys_base; /* Bt848 register physical address */ +#if !defined(__NetBSD__) && !defined(__OpenBSD__) + pcici_t tag; /* PCI tag, for doing PCI commands */ +#endif + vm_offset_t bigbuf; /* buffer that holds the captured image */ + int alloc_pages; /* number of pages in bigbuf */ + struct proc *proc; /* process to receive raised signal */ + int signal; /* signal to send to process */ +#define METEOR_SIG_MODE_MASK 0xffff0000 +#define METEOR_SIG_FIELD_MODE 0x00010000 +#define METEOR_SIG_FRAME_MODE 0x00000000 + vm_offset_t dma_prog; + vm_offset_t odd_dma_prog; + char dma_prog_loaded; + struct meteor_mem *mem; /* used to control sync. multi-frame output */ + u_long synch_wait; /* wait for free buffer before continuing */ + short current; /* frame number in buffer (1-frames) */ + short rows; /* number of rows in a frame */ + short cols; /* number of columns in a frame */ + int pixfmt; /* active pixel format (idx into fmt tbl) */ + int pixfmt_compat; /* Y/N - in meteor pix fmt compat mode */ + u_long format; /* frame format rgb, yuv, etc.. */ + short frames; /* number of frames allocated */ + int frame_size; /* number of bytes in a frame */ + u_long fifo_errors; /* number of fifo capture errors since open */ + u_long dma_errors; /* number of DMA capture errors since open */ + u_long frames_captured;/* number of frames captured since open */ + u_long even_fields_captured; /* number of even fields captured */ + u_long odd_fields_captured; /* number of odd fields captured */ + u_long range_enable; /* enable range checking ?? */ + u_short capcontrol; /* reg 0xdc capture control */ + u_short bktr_cap_ctl; + volatile u_int flags; +#define METEOR_INITALIZED 0x00000001 +#define METEOR_OPEN 0x00000002 +#define METEOR_MMAP 0x00000004 +#define METEOR_INTR 0x00000008 +#define METEOR_READ 0x00000010 /* XXX never gets referenced */ +#define METEOR_SINGLE 0x00000020 /* get single frame */ +#define METEOR_CONTIN 0x00000040 /* continuously get frames */ +#define METEOR_SYNCAP 0x00000080 /* synchronously get frames */ +#define METEOR_CAP_MASK 0x000000f0 +#define METEOR_NTSC 0x00000100 +#define METEOR_PAL 0x00000200 +#define METEOR_SECAM 0x00000400 +#define METEOR_AUTOMODE 0x00000800 +#define METEOR_FORM_MASK 0x00000f00 +#define METEOR_DEV0 0x00001000 +#define METEOR_DEV1 0x00002000 +#define METEOR_DEV2 0x00004000 +#define METEOR_DEV3 0x00008000 +#define METEOR_DEV_SVIDEO 0x00006000 +#define METEOR_DEV_RGB 0x0000a000 +#define METEOR_DEV_MASK 0x0000f000 +#define METEOR_RGB16 0x00010000 +#define METEOR_RGB24 0x00020000 +#define METEOR_YUV_PACKED 0x00040000 +#define METEOR_YUV_PLANAR 0x00080000 +#define METEOR_WANT_EVEN 0x00100000 /* want even frame */ +#define METEOR_WANT_ODD 0x00200000 /* want odd frame */ +#define METEOR_WANT_MASK 0x00300000 +#define METEOR_ONLY_EVEN_FIELDS 0x01000000 +#define METEOR_ONLY_ODD_FIELDS 0x02000000 +#define METEOR_ONLY_FIELDS_MASK 0x03000000 +#define METEOR_YUV_422 0x04000000 +#define METEOR_OUTPUT_FMT_MASK 0x040f0000 +#define METEOR_WANT_TS 0x08000000 /* time-stamp a frame */ +#define METEOR_RGB 0x20000000 /* meteor rgb unit */ +#define METEOR_FIELD_MODE 0x80000000 + u_char tflags; +#define TUNER_INITALIZED 0x00000001 +#define TUNER_OPEN 0x00000002 + u_short fps; /* frames per second */ + struct meteor_video video; + struct TVTUNER tuner; + struct CARDTYPE card; + u_char audio_mux_select; /* current mode of the audio */ + u_char audio_mute_state; /* mute state of the audio */ + u_char format_params; + u_long current_sol; + u_long current_col; + int clip_start; + int line_length; + int last_y; + int y; + int y2; + int yclip; + int yclip2; + int max_clip_node; + bktr_clip_t clip_list[100]; +}; + +typedef struct bktr_softc bktr_reg_t; +typedef struct bktr_softc* bktr_ptr_t; diff --git a/sys/dev/pci/brooktree848.c b/sys/dev/pci/brooktree848.c new file mode 100644 index 00000000000..5e377cffc10 --- /dev/null +++ b/sys/dev/pci/brooktree848.c @@ -0,0 +1,5378 @@ +/* BT848 1.30 Driver for Brooktree's Bt848 based cards. + The Brooktree BT848 Driver driver is based upon Mark Tinguely and + Jim Lowe's driver for the Matrox Meteor PCI card . The + Philips SAA 7116 and SAA 7196 are very different chipsets than + the BT848. For starters, the BT848 is a one chipset solution and + it incorporates a RISC engine to control the DMA transfers -- + that is it the actual dma process is control by a program which + resides in the hosts memory also the register definitions between + the Philips chipsets and the Bt848 are very different. + + The original copyright notice by Mark and Jim is included mostly + to honor their fantastic work in the Matrox Meteor driver! + + Enjoy, + Amancio + + */ + +/* + * 1. Redistributions of source code must retain the + * Copyright (c) 1997 Amancio Hasty + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Amancio Hasty + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + + + +/* + * 1. Redistributions of source code must retain the + * Copyright (c) 1995 Mark Tinguely and Jim Lowe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Tinguely and Jim Lowe + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Change History: +1.0 1/24/97 First Alpha release + +1.1 2/20/97 Added video ioctl so we can do PCI To PCI + data transfers. This is for capturing data + directly to a vga frame buffer which has + a linear frame buffer. Minor code clean-up. + +1.3 2/23/97 Fixed system lock-up reported by + Randall Hopper <rhh@ct.picker.com>. This + problem seems somehow to be exhibited only + in his system. I changed the setting of + INT_MASK for CAP_CONTINUOUS to be exactly + the same as CAP_SINGLE apparently setting + bit 23 cleared the system lock up. + version 1.1 of the driver has been reported + to work with STB's WinTv, Hauppage's Wincast/Tv + and last but not least with the Intel Smart + Video Recorder. + +1.4 3/9/97 fsmp@freefall.org + Merged code to support tuners on STB and WinCast + cards. + Modifications to the contrast and chroma ioctls. + Textual cleanup. + +1.5 3/15/97 fsmp@freefall.org + new bt848 specific versions of hue/bright/ + contrast/satu/satv. + Amancio's patch to fix "screen freeze" problem. + +1.6 3/19/97 fsmp@freefall.org + new table-driven frequency lookup. + removed disable_intr()/enable_intr() calls from i2c. + misc. cleanup. + +1.7 3/19/97 fsmp@freefall.org + added audio support submitted by: + Michael Petry <petry@netwolf.NetMasters.com> + +1.8 3/20/97 fsmp@freefall.org + extended audio support. + card auto-detection. + major cleanup, order of routines, declarations, etc. + +1.9 3/22/97 fsmp@freefall.org + merged in Amancio's minor unit for tuner control + mods. + misc. cleanup, especially in the _intr routine. + made AUDIO_SUPPORT mainline code. + +1.10 3/23/97 fsmp@freefall.org + added polled hardware i2c routines, + removed all existing software i2c routines. + created software i2cProbe() routine. + Randall Hopper's fixes of BT848_GHUE & BT848_GBRIG. + eeprom support. + +1.11 3/24/97 fsmp@freefall.org + Louis Mamakos's new bt848 struct. + +1.12 3/25/97 fsmp@freefall.org + japanese freq table from Naohiro Shichijo. + new table structs for tuner lookups. + major scrub for "magic numbers". + +1.13 3/28/97 fsmp@freefall.org + 1st PAL support. + MAGIC_[1-4] demarcates magic #s needing PAL work. + AFC code submitted by Richard Tobin + <richard@cogsci.ed.ac.uk>. + +1.14 3/29/97 richard@cogsci.ed.ac.uk + PAL support: magic numbers moved into + format_params structure. + Revised AFC interface. + fixed DMA_PROG_ALLOC size misdefinition. + +1.15 4/18/97 John-Mark Gurney <gurney_j@resnet.uoregon.edu> + Added [SR]RGBMASKs ioctl for byte swapping. + +1.16 4/20/97 Randall Hopper <rhh@ct.picker.com> + Generalized RGBMASK ioctls for general pixel + format setting [SG]ACTPIXFMT, and added query API + to return driver-supported pix fmts GSUPPIXFMT. + +1.17 4/21/97 hasty@rah.star-gate.com + Clipping support added. + +1.18 4/23/97 Clean up after failed CAP_SINGLEs where bt + interrupt isn't delivered, and fixed fixing + CAP_SINGLEs that for ODD_ONLY fields. +1.19 9/8/97 improved yuv support , cleaned up weurope + channel table, incorporated cleanup work from + Luigi, fixed pci interface bug due to a + change in the pci interface which disables + interrupts from a PCI device by default, + Added Luigi's, ioctl's BT848_SLNOTCH, + BT848_GLNOTCH (set luma notch and get luma not) +1.20 10/5/97 Keith Sklower <sklower@CS.Berkeley.EDU> submitted + a patch to fix compilation of the BSDI's PCI + interface. + Hideyuki Suzuki <hideyuki@sat.t.u-tokyo.ac.jp> + Submitted a patch for Japanese cable channels + Joao Carlos Mendes Luis jonny@gta.ufrj.br + Submitted general ioctl to set video broadcast + formats (PAL, NTSC, etc..) previously we depended + on the Bt848 auto video detect feature. +1.21 10/24/97 Randall Hopper <rhh@ct.picker.com> + Fix temporal decimation, disable it when + doing CAP_SINGLEs, and in dual-field capture, don't + capture fields for different frames +1.22 11/08/97 Randall Hopper <rhh@ct.picker.com> + Fixes for packed 24bpp - FIFO alignment +1.23 11/17/97 Amancio <hasty@star-gate.com> + Added yuv support mpeg encoding +1.24 12/27/97 Jonathan Hanna <pangolin@rogers.wave.ca> + Patch to support Philips FR1236MK2 tuner +1.25 02/02/98 Takeshi Ohashi + <ohashi@atohasi.mickey.ai.kyutech.ac.jp> submitted + code to support bktr_read . + Flemming Jacobsen <fj@schizo.dk.tfs.com> + submitted code to support radio available with in + some bt848 based cards;additionally, wrote code to + correctly recognized his bt848 card. + Roger Hardiman <roger@cs.strath.ac.uk> submitted + various fixes to smooth out the microcode and made + all modes consistent. +1.26 Moved Luigi's I2CWR ioctl from the video_ioctl + section to the tuner_ioctl section + Changed Major device from 79 to 92 and reserved + our Major device number -- hasty@star-gate.com +1.27 Last batch of patches for radio support from + Flemming Jacobsen <fj@trw.nl>. + Added B849 PCI ID submitted by: + Tomi Vainio <tomppa@fidata.fi> +1.28 Frank Nobis <fn@Radio-do.de> added tuner support + for the German Phillips PAL tuner and + additional channels for german cable tv. +1.29 Roger Hardiman <roger@cs.strath.ac.uk> + Revised autodetection code to correctly handle both + old and new VideoLogic Captivator PCI cards. + Added tsleep of 2 seconds to initialistion code + for PAL users.Corrected clock selection code on + format change. +1.30 Bring back Frank Nobis <fn@Radio-do.de>'s opt_bktr.h + +*/ + +#define OVERRIDE_CARD CARD_MIRO +#define OVERRIDE_TUNER PHILIPS_SECAM + +#if !defined(__NetBSD__) && !defined(__OpenBSD__) +#define DDB(x) x +#define DEB(x) +#endif + +#ifdef __FreeBSD__ +#include "bktr.h" +#include "opt_devfs.h" +#include "pci.h" +#endif /* __FreeBSD__ */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include "bktr.h" +#include "pci.h" +#endif /* __NetBSD__ || __OpenBSD__ */ + +#if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) || (NBKTR > 0 && NPCI > 0) + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/signalvar.h> +#include <sys/mman.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/pmap.h> +#include <vm/vm_extern.h> + +#ifdef __FreeBSD__ +#ifdef DEVFS +#include <sys/devfsext.h> +#endif /* DEVFS */ +#include <machine/clock.h> +#include <pci/pcivar.h> +#include <pci/pcireg.h> + +#include <machine/ioctl_meteor.h> +#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ +#include <pci/brktree_reg.h> + +typedef int ioctl_cmd_t; +#endif /* __FreeBSD__ */ + +#ifdef __bsdi__ +#include <sys/device.h> +#include <i386/isa/isa.h> +#include <i386/isa/isavar.h> +#include <i386/isa/icu.h> +#include <i386/pci/pci.h> +#include <i386/isa/dma.h> +#include <i386/eisa/eisa.h> +#include "ioctl_meteor.h" +#include "ioctl_bt848.h" +#include "bt848_reg.h" + +typedef u_long ioctl_cmd_t; + +#define pci_conf_read(a, r) pci_inl(a, r) +#define pci_conf_write(a, r, v) pci_outl(a, r, v) +#include <sys/reboot.h> +#define bootverbose (autoprint & (AC_VERBOSE|AC_DEBUG)) +#endif /* __bsdi__ */ + +#if defined(__OpenBSD__) +#include <sys/malloc.h> +#include <sys/proc.h> +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include <sys/device.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <machine/bus.h> +#include <machine/ioctl_meteor.h> +#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ +#include <dev/pci/brktree_reg.h> + +typedef int ioctl_cmd_t; + +static int bootverbose = 1; + +#define BKTR_DEBUG +#ifdef BKTR_DEBUG +int bktr_debug = 0; +#define DPR(x) (bktr_debug ? printf x : 0) +#else +#define DPR(x) +#endif + +#endif /* __NetBSD__ || __OpenBSD__ */ + +typedef u_char bool_t; + +#define BKTRPRI (PZERO+8)|PCATCH + +#if defined(__NetBSD__) || defined(__OpenBSD__) +static int bktr_intr __P((void *arg)); +#else +static void bktr_intr __P((void *arg)); +#endif + + +/* + * memory allocated for DMA programs + */ +#define DMA_PROG_ALLOC (8 * PAGE_SIZE) + +/* When to split a dma transfer , the bt848 has timing as well as + dma transfer size limitations so that we have to split dma + transfers into two dma requests + */ +#define DMA_BT848_SPLIT 319*2 + +/* + * Allocate enough memory for: + * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages + * + * You may override this using the options "BROOKTREE_ALLOC_PAGES=value" + * in your kernel configuration file. + */ + +#ifndef BROOKTREE_ALLOC_PAGES +#define BROOKTREE_ALLOC_PAGES 217*4 +#endif +#define BROOKTREE_ALLOC (BROOKTREE_ALLOC_PAGES * PAGE_SIZE) + +/* Defines for fields */ +#define ODD_F 0x01 +#define EVEN_F 0x02 + +#ifdef __FreeBSD__ + +static bktr_reg_t brooktree[ NBKTR ]; +#define BROOKTRE_NUM(mtr) ((bktr - &brooktree[0])/sizeof(bktr_reg_t)) + +#define UNIT(x) ((x) & 0x0f) +#define MINOR(x) ((x >> 4) & 0x0f) +#define ATTACH_ARGS pcici_t tag, int unit + +static char* bktr_probe( pcici_t tag, pcidi_t type ); +static void bktr_attach( ATTACH_ARGS ); + +static u_long bktr_count; + +static struct pci_device bktr_device = { + "bktr", + bktr_probe, + bktr_attach, + &bktr_count +}; + +DATA_SET (pcidevice_set, bktr_device); + +static d_open_t bktr_open; +static d_close_t bktr_close; +static d_read_t bktr_read; +static d_write_t bktr_write; +static d_ioctl_t bktr_ioctl; +static d_mmap_t bktr_mmap; + +#define CDEV_MAJOR 92 +static struct cdevsw bktr_cdevsw = +{ + bktr_open, bktr_close, bktr_read, bktr_write, + bktr_ioctl, nostop, nullreset, nodevtotty, + seltrue, bktr_mmap, NULL, "bktr", + NULL, -1 +}; +#endif /* __FreeBSD__ */ + +#ifdef __bsdi__ +#define UNIT dv_unit +#define MINOR dv_subunit +#define ATTACH_ARGS \ + struct device * const parent, struct device * const self, void * const aux + +#define PCI_COMMAND_STATUS_REG PCI_COMMAND + +static void bktr_attach( ATTACH_ARGS ); +#define NBKTR bktrcd.cd_ndevs +#define brooktree *((bktr_ptr_t *)bktrcd.cd_devs) + +static int bktr_spl; +static int bktr_intr_returning_1(void *arg) { bktr_intr(arg); return (1);} +#define disable_intr() { bktr_spl = splhigh(); } +#define enable_intr() { splx(bktr_spl); } + +static int +bktr_pci_match(pci_devaddr_t *pa) +{ + unsigned id; + + id = pci_inl(pa, PCI_VENDOR_ID); + + if (id == BROOKTREE_848_ID || id == BROOKTREE_849_ID ) { + return 1; + } + aprint_debug("bktr_pci_match got %x\n", id); + return 0; + +} + +pci_devres_t bktr_res; /* XXX only remembers last one, helps debug */ + +static int +bktr_probe(struct device *parent, struct cfdata *cf, void *aux) +{ + pci_devaddr_t *pa; + pci_devres_t res; + struct isa_attach_args *ia = aux; + + if (ia->ia_bustype != BUS_PCI) + return (0); + + if ((pa = pci_scan(bktr_pci_match)) == NULL) + return (0); + + pci_getres(pa, &bktr_res, 1, ia); + if (ia->ia_maddr == 0) { + printf("bktr%d: no mem attached\n", cf->cf_unit); + return (0); + } + ia->ia_aux = pa; + return 1; +} + + +struct cfdriver bktrcd = +{ 0, "bktr", bktr_probe, bktr_attach, DV_DULL, sizeof(bktr_reg_t) }; + +int bktr_open __P((dev_t, int, int, struct proc *)); +int bktr_close __P((dev_t, int, int, struct proc *)); +int bktr_read __P((dev_t, struct uio *, int)); +int bktr_write __P((dev_t, struct uio *, int)); +int bktr_ioctl __P((dev_t, ioctl_cmd_t, caddr_t, int, struct proc *)); +int bktr_mmap __P((dev_t, int, int)); + +struct devsw bktrsw = { + &bktrcd, + bktr_open, bktr_close, bktr_read, bktr_write, bktr_ioctl, + seltrue, bktr_mmap, NULL, nodump, NULL, 0, nostop +}; +#endif /* __bsdi__ */ + +#if defined(__NetBSD__) || defined(__OpenBSD__) + +#define IPL_VIDEO IPL_BIO /* XXX */ +#define UNIT(x) ((x) & 0x0f) +#define MINOR(x) ((x >> 4) & 0x0f) + +#define ATTACH_ARGS struct device *parent, struct device *self, void *aux + +#define bktr_open bktropen +#define bktr_close bktrclose +#define bktr_read bktrread +#define bktr_write bktrwrite +#define bktr_ioctl bktrioctl +#define bktr_mmap bktrmmap + +int bktr_open __P((dev_t, int, int, struct proc *)); +int bktr_close __P((dev_t, int, int, struct proc *)); +int bktr_read __P((dev_t, struct uio *, int)); +int bktr_write __P((dev_t, struct uio *, int)); +int bktr_ioctl __P((dev_t, ioctl_cmd_t, caddr_t, int, struct proc*)); +int bktr_mmap __P((dev_t, int, int)); + +vm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t, + vm_offset_t, vm_offset_t); + +#if defined(__BROKEN_INDIRECT_CONFIG) || defined(__OpenBSD__) +static int bktr_probe __P((struct device *, void *, void *)); +#else +static int bktr_probe __P((struct device *, struct cfdata *, void *)); +#endif +static void bktr_attach __P((struct device *, struct device *, void *)); + +struct cfattach bktr_ca = { + sizeof(struct bktr_softc), bktr_probe, bktr_attach +}; + +#if 0 +extern struct cfdriver bktr_cd; +#else +struct cfdriver bktr_cd = { + NULL, "bktr", DV_DULL +}; +#endif + +int bktr_probe(parent, match, aux) + struct device *parent; +#if defined(__BROKEN_INDIRECT_CONFIG) || defined(__OpenBSD__) + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + struct pci_attach_args *pa = aux; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE && + (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849)) + return 1; + + return 0; +} + +#endif /* __NetBSD__ || __OpenBSD__ */ + +/* + * This is for start-up convenience only, NOT mandatory. + */ +#if !defined( DEFAULT_CHNLSET ) +#define DEFAULT_CHNLSET CHNLSET_WEUROPE +#endif + +/* + * Parameters describing size of transmitted image. + */ + +static struct format_params format_params[] = { +/* # define BT848_IFORM_F_AUTO (0x0) - don't matter. */ + { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_AUTO }, +/* # define BT848_IFORM_F_NTSCM (0x1) */ + { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0 }, +/* # define BT848_IFORM_F_NTSCJ (0x2) */ + { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0 }, +/* # define BT848_IFORM_F_PALBDGHI (0x3) */ + { 625, 32, 576, 1135, 186, 922, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1 }, +/* # define BT848_IFORM_F_PALM (0x4) */ + { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0 }, +/*{ 625, 32, 576, 910, 186, 922, 640, 780, 25, 0x68, 0x5d, BT848_IFORM_X_XT0 }, */ +/* # define BT848_IFORM_F_PALN (0x5) */ + { 625, 32, 576, 1135, 186, 922, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1 }, +/* # define BT848_IFORM_F_SECAM (0x6) */ + { 625, 32, 576, 1135, 186, 922, 768, 944, 25, 0x7f, 0x00, BT848_IFORM_X_XT1 }, +/* # define BT848_IFORM_F_RSVD (0x7) - ???? */ + { 625, 32, 576, 1135, 186, 922, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT0 }, +}; + +/* + * Table of supported Pixel Formats + */ + +static struct meteor_pixfmt_internal { + struct meteor_pixfmt public; + u_int color_fmt; +} pixfmt_table[] = { + +{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0,0 }, 0x33 }, +{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 1,0 }, 0x33 }, + +{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 0,0 }, 0x22 }, +{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 1,0 }, 0x22 }, + +{ { 0, METEOR_PIXTYPE_RGB, 3, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x11 }, + +{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,0 }, 0x00 }, +{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x00 }, +{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x00 }, +{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x00 }, +{ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 }, +{ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x44 }, +{ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 }, + +}; +#define PIXFMT_TABLE_SIZE ( sizeof(pixfmt_table) / sizeof(pixfmt_table[0]) ) + +/* + * Table of Meteor-supported Pixel Formats (for SETGEO compatibility) + */ + +/* FIXME: Also add YUV_422 and YUV_PACKED as well */ +static struct { + u_long meteor_format; + struct meteor_pixfmt public; +} meteor_pixfmt_table[] = { + { METEOR_GEO_YUV_12, + { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 } + }, + + /* FIXME: Should byte swap flag be on for this one; negative in drvr? */ + { METEOR_GEO_YUV_422, + { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 } + }, + { METEOR_GEO_YUV_PACKED, + { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 } + }, + { METEOR_GEO_RGB16, + { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0, 0 } + }, + { METEOR_GEO_RGB24, + { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000, 0x00ff00, 0x0000ff }, 0, 0 } + }, + +}; +#define METEOR_PIXFMT_TABLE_SIZE ( sizeof(meteor_pixfmt_table) / \ + sizeof(meteor_pixfmt_table[0]) ) + + +#define BSWAP (BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN) +#define WSWAP (BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN) + + +/* experimental code for Automatic Frequency Control */ +#define TUNER_AFC +#define TEST_TUNER_AFC_NOT + +#if defined( TUNER_AFC ) +#define AFC_DELAY 10000 /* 10 millisend delay */ +#define AFC_BITS 0x07 +#define AFC_FREQ_MINUS_125 0x00 +#define AFC_FREQ_MINUS_62 0x01 +#define AFC_FREQ_CENTERED 0x02 +#define AFC_FREQ_PLUS_62 0x03 +#define AFC_FREQ_PLUS_125 0x04 +#define AFC_MAX_STEP (5 * FREQFACTOR) /* no more than 5 MHz */ +#endif /* TUNER_AFC */ + +/* + * i2c things: + */ + +/* PLL on a Temic NTSC tuner: 4032FY5 */ +#define TEMIC_NTSC_WADDR 0xc0 +#define TEMIC_NTSC_RADDR 0xc1 + +/* PLL on a Temic PAL I tuner: 4062FY5 */ +#define TEMIC_PALI_WADDR 0xc2 +#define TEMIC_PALI_RADDR 0xc3 + +/* PLL on a Philips tuner */ +#define PHILIPS_NTSC_WADDR 0xc6 +#define PHILIPS_NTSC_RADDR 0xc7 + +/* PLL on a the Philips FR1236MK2 tuner */ +#define PHILIPS_FR1236_NTSC_WADDR 0xc2 +#define PHILIPS_FR1236_NTSC_RADDR 0xc3 + +/* PLL on a the Philips FR1216MK2 tuner, + yes, the european version of the tuner is 1216 */ +#define PHILIPS_FR1216_PAL_WADDR 0xc2 +#define PHILIPS_FR1216_PAL_RADDR 0xc3 + +/* guaranteed address for any TSA5522/3 (PLL on all(?) tuners) */ +#define TSA552x_WADDR 0xc2 +#define TSA552x_RADDR 0xc3 + +#define PHILIPS_PAL_WADDR 0xc2 +#define PHILIPS_PAL_RADDR 0xc3 + + +#define TSA552x_CB_MSB (0x80) +#define TSA552x_CB_CP (1<<6) +#define TSA552x_CB_T2 (1<<5) +#define TSA552x_CB_T1 (1<<4) +#define TSA552x_CB_T0 (1<<3) +#define TSA552x_CB_RSA (1<<2) +#define TSA552x_CB_RSB (1<<1) +#define TSA552x_CB_OS (1<<0) +#define TSA552x_RADIO (TSA552x_CB_MSB | \ + TSA552x_CB_T0) + +/* Add RADIO_OFFSET to the "frequency" to indicate that we want to tune */ +/* the radio (if present) not the TV tuner. */ +/* 20000 is equivalent to 20000MHz/16 = 1.25GHz - this area is unused. */ +#define RADIO_OFFSET 20000 + + +/* address of BTSC/SAP decoder chip */ +#define TDA9850_WADDR 0xb6 +#define TDA9850_RADDR 0xb7 + +/* address of MSP3400C chip */ +#define MSP3400C_WADDR 0x80 +#define MSP3400C_RADDR 0x81 + + +/* EEProm (128 * 8) on an STB card */ +#define X24C01_WADDR 0xae +#define X24C01_RADDR 0xaf + + +/* EEProm (256 * 8) on a Hauppauge card */ +#define PFC8582_WADDR 0xa0 +#define PFC8582_RADDR 0xa1 + + +/* registers in the BTSC/dbx chip */ +#define CON1ADDR 0x04 +#define CON2ADDR 0x05 +#define CON3ADDR 0x06 +#define CON4ADDR 0x07 + + +/* raise the charge pump voltage for fast tuning */ +#define TSA552x_FCONTROL (TSA552x_CB_MSB | \ + TSA552x_CB_CP | \ + TSA552x_CB_T0 | \ + TSA552x_CB_RSA | \ + TSA552x_CB_RSB) + +/* lower the charge pump voltage for better residual oscillator FM */ +#define TSA552x_SCONTROL (TSA552x_CB_MSB | \ + TSA552x_CB_T0 | \ + TSA552x_CB_RSA | \ + TSA552x_CB_RSB) + +/* sync detect threshold */ +#if 0 +#define SYNC_LEVEL (BT848_ADC_RESERVED | \ + BT848_ADC_CRUSH) /* threshold ~125 mV */ +#else +#define SYNC_LEVEL (BT848_ADC_RESERVED | \ + BT848_ADC_SYNC_T) /* threshold ~75 mV */ +#endif + + +/* the GPIO bits that control the audio MUXes */ +#define GPIO_AUDIOMUX_BITS 0x0f + + +/* debug utility for holding previous INT_STAT contents */ +#define STATUS_SUM +static u_long status_sum = 0; + +/* + * defines to make certain bit-fiddles understandable + */ +#define FIFO_ENABLED BT848_DMA_CTL_FIFO_EN +#define RISC_ENABLED BT848_DMA_CTL_RISC_EN +#define FIFO_RISC_ENABLED (BT848_DMA_CTL_FIFO_EN | BT848_DMA_CTL_RISC_EN) +#define FIFO_RISC_DISABLED 0 + +#define ALL_INTS_DISABLED 0 +#define ALL_INTS_CLEARED 0xffffffff +#define CAPTURE_OFF 0 + +#define BIT_SEVEN_HIGH (1<<7) +#define BIT_EIGHT_HIGH (1<<8) + +#define I2C_BITS (BT848_INT_RACK | BT848_INT_I2CDONE) +#define TDEC_BITS (BT848_INT_FDSR | BT848_INT_FBUS) + + +/* + * misc. support routines. + */ +static int signCard( bktr_ptr_t bktr, int offset, + int count, u_char* sig ); +static void probeCard( bktr_ptr_t bktr, int verbose ); + + +#if defined(__NetBSD__) || defined(__OpenBSD__) +static vm_offset_t get_bktr_mem(bktr_ptr_t, bus_dmamap_t *, + unsigned size); +static void free_bktr_mem(bktr_ptr_t, bus_dmamap_t, + vm_offset_t); +#else +static vm_offset_t get_bktr_mem( int unit, unsigned size ); +#endif + +static int oformat_meteor_to_bt( u_long format ); + +static u_int pixfmt_swap_flags( int pixfmt ); + +/* + * bt848 RISC programming routines. + */ +#ifdef BT848_DUMP +static int dump_bt848( bt848_ptr_t bt848 ); +#endif + +static void yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols, + int rows, int interlace ); +static void yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols, + int rows, int interlace ); +static void yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols, + int rows, int interlace ); +static void rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, + int rows, int interlace ); +static void build_dma_prog( bktr_ptr_t bktr, char i_flag ); + +static bool_t getline(bktr_reg_t *, int); +static bool_t notclipped(bktr_reg_t * , int , int); +static bool_t split(bktr_reg_t *, volatile u_long **, int, u_long, int, + volatile u_char ** , int ); + +/* + * video & video capture specific routines. + */ +static int video_open( bktr_ptr_t bktr ); +static int video_close( bktr_ptr_t bktr ); +static int video_ioctl( bktr_ptr_t bktr, int unit, + int cmd, caddr_t arg, struct proc* pr ); + +static void start_capture( bktr_ptr_t bktr, unsigned type ); +static void set_fps( bktr_ptr_t bktr, u_short fps ); + + +/* + * tuner specific functions. + */ +static int tuner_open( bktr_ptr_t bktr ); +static int tuner_close( bktr_ptr_t bktr ); +static int tuner_ioctl( bktr_ptr_t bktr, int unit, + int cmd, caddr_t arg, struct proc* pr ); + +static int tv_channel( bktr_ptr_t bktr, int channel ); +static int tv_freq( bktr_ptr_t bktr, int frequency ); +#if defined( TUNER_AFC ) +static int do_afc( bktr_ptr_t bktr, int addr, int frequency ); +#endif /* TUNER_AFC */ + + +/* + * audio specific functions. + */ +static int set_audio( bktr_ptr_t bktr, int mode ); +static void temp_mute( bktr_ptr_t bktr, int flag ); +static int set_BTSC( bktr_ptr_t bktr, int control ); + + +/* + * ioctls common to both video & tuner. + */ +static int common_ioctl( bktr_ptr_t bktr, bt848_ptr_t bt848, + int cmd, caddr_t arg ); + + +/* + * i2c primitives + */ +static int i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ); +static int i2cRead( bktr_ptr_t bktr, int addr ); +static int writeEEProm( bktr_ptr_t bktr, int offset, int count, + u_char* data ); +static int readEEProm( bktr_ptr_t bktr, int offset, int count, + u_char* data ); + + +#ifdef __FreeBSD__ +/* + * the boot time probe routine. + */ +static char* +bktr_probe( pcici_t tag, pcidi_t type ) +{ + switch (type) { + case BROOKTREE_848_ID: + return("BrookTree 848"); + case BROOKTREE_849_ID: + return("BrookTree 849"); + }; + + return ((char *)0); +} +#endif /* __FreeBSD__ */ + + + + +/* + * the attach routine. + */ +static void +bktr_attach( ATTACH_ARGS ) +{ + bktr_ptr_t bktr; + bt848_ptr_t bt848; +#ifdef BROOKTREE_IRQ + u_long old_irq, new_irq; +#endif + vm_offset_t buf; + u_long latency; + u_long fun; + +#ifdef __FreeBSD__ + bktr = &brooktree[unit]; + + if (unit >= NBKTR) { + printf("brooktree%d: attach: only %d units configured.\n", + unit, NBKTR); + printf("brooktree%d: attach: invalid unit number.\n", unit); + return; + } + + bktr->tag = tag; + pci_map_mem( tag, PCI_MAP_REG_START, (vm_offset_t *) &bktr->base, + &bktr->phys_base ); + + +#ifdef BROOKTREE_IRQ /* from the configuration file */ + old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); + pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ); + new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); + printf("bktr%d: attach: irq changed from %d to %d\n", + unit, (old_irq & 0xff), (new_irq & 0xff)); +#endif + /* setup the interrupt handling routine */ + pci_map_int(tag, bktr_intr, (void*) bktr, &net_imask); +#endif /* __FreeBSD__ */ + +#ifdef __bsdi__ + struct isa_attach_args * const ia = (struct isa_attach_args *)aux; + pci_devaddr_t *tag = (pci_devaddr_t *) ia->ia_aux; + int unit = bktr->bktr_dev.dv_unit; + + bktr = (bktr_reg_t *) self; + bktr->base = (bt848_ptr_t) bktr_res.pci_vaddr; + isa_establish(&bktr->bktr_id, &bktr->bktr_dev); + bktr->bktr_ih.ih_fun = bktr_intr_returning_1; + bktr->bktr_ih.ih_arg = (void *)bktr; + intr_establish(ia->ia_irq, &bktr->bktr_ih, DV_DULL); +#endif /* __bsdi__ */ + +#if defined(__OpenBSD__) + struct pci_attach_args *pa = aux; + pci_chipset_tag_t pc = pa->pa_pc; + + pci_intr_handle_t ih; + const char *intrstr; + int retval; + int unit; + + bktr = (bktr_ptr_t)self; + unit = bktr->bktr_dev.dv_unit; + + printf("\n"); + + /* + * map memory + */ + bktr->memt = pa->pa_memt; + retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START, + &bktr->phys_base, &bktr->obmemsz, NULL); + if (!retval) + retval = bus_space_map(pa->pa_memt, bktr->phys_base, + bktr->obmemsz, 0, &bktr->memh); + if (retval) { + printf("%s: couldn't map memory\n", bktr->bktr_dev.dv_xname); + return; + } + bktr->base = (bt848_ptr_t)bktr->memh; + + + /* + * map interrupt + */ + if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &ih)) { + printf("%s: couldn't map interrupt\n", bktr->bktr_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pa->pa_pc, ih); + + bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO, + bktr_intr, bktr, bktr->bktr_dev.dv_xname); + if (bktr->ih == NULL) { + printf("%s: couldn't establish interrupt", + bktr->bktr_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + + if (intrstr != NULL) + printf("%s: interrupting at %s\n", bktr->bktr_dev.dv_xname, + intrstr); +#endif /* __OpenBSD__ */ + +#if defined(__NetBSD__) + struct pci_attach_args *pa = aux; + pci_intr_handle_t ih; + const char *intrstr; + int retval; + int unit; + + bktr = (bktr_ptr_t)self; + unit = bktr->bktr_dev.dv_unit; + + /* + * map memory + */ + retval = pci_mapreg_map(pa, PCI_MAPREG_START, + PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, + &bktr->memt, &bktr->memh, &bktr->phys_base, + &bktr->obmemsz); + DPR(("pci_mapreg_map: memt %x, memh %x, base %x, size %x\n", + bktr->memt, (u_int)bktr->memh, + (u_int)bktr->phys_base, (u_int)bktr->obmemsz)); + bktr->base = (bt848_ptr_t)bktr->memh; /* XXX */ + if (retval) { + printf("%s: couldn't map memory\n", bktr->bktr_dev.dv_xname); + return; + } + + /* + * map interrupt + */ + if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &ih)) { + printf("%s: couldn't map interrupt\n", bktr->bktr_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pa->pa_pc, ih); + bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO, + bktr_intr, bktr, bktr->bktr_dev.dv_xname); + if (bktr->ih == NULL) { + printf("%s: couldn't establish interrupt", + bktr->bktr_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + if (intrstr != NULL) + printf("%s: interrupting at %s\n", bktr->bktr_dev.dv_xname, + intrstr); +#endif /* __NetBSD__ */ + +/* + * PCI latency timer. 32 is a good value for 4 bus mastering slots, if + * you have more than four, then 16 would probably be a better value. + */ +#ifndef BROOKTREE_DEF_LATENCY_VALUE +#define BROOKTREE_DEF_LATENCY_VALUE 10 +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) + latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER); + latency = (latency >> 8) & 0xff; + if ( bootverbose ) { + if (latency) + printf("bktr%d: PCI bus latency is", unit); + else + printf("bktr%d: PCI bus latency was 0 changing to", + unit); + } + if ( !latency ) { + latency = BROOKTREE_DEF_LATENCY_VALUE; + pci_conf_write(pa->pa_pc, pa->pa_tag, + PCI_LATENCY_TIMER, latency<<8); + } +#else /* !__NetBSD__ || __OpenBSD__ */ + latency = pci_conf_read(tag, PCI_LATENCY_TIMER); + latency = (latency >> 8) & 0xff; + if ( bootverbose ) { + if (latency) + printf("brooktree%d: PCI bus latency is", unit); + else + printf("brooktree%d: PCI bus latency was 0 changing to", + unit); + } + if ( !latency ) { + latency = BROOKTREE_DEF_LATENCY_VALUE; + pci_conf_write(tag, PCI_LATENCY_TIMER, latency<<8); + } +#endif /* !__NetBSD__ && !__OpenBSD__ */ + if ( bootverbose ) { + printf(" %d.\n", (int) latency); + } + + +#if defined(__NetBSD__) || defined(__OpenBSD__) + /* allocate space for dma program */ + bktr->dmat = pa->pa_dmat; + bktr->dma_prog = get_bktr_mem(bktr, &bktr->dm_prog, DMA_PROG_ALLOC); + bktr->odd_dma_prog = get_bktr_mem(bktr, &bktr->dm_oprog, DMA_PROG_ALLOC); + /* allocate space for pixel buffer */ + if ( BROOKTREE_ALLOC ) + buf = get_bktr_mem(bktr, &bktr->dm_mem, BROOKTREE_ALLOC); + else + buf = 0; +#else + /* allocate space for dma program */ + bktr->dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC); + bktr->odd_dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC); + + /* allocate space for pixel buffer */ + if ( BROOKTREE_ALLOC ) + buf = get_bktr_mem(unit, BROOKTREE_ALLOC); + else + buf = 0; + +#endif + + if ( bootverbose ) { + printf("bktr%d: buffer size %d, addr 0x%x\n", + unit, BROOKTREE_ALLOC, vtophys(buf)); + } + + bktr->bigbuf = buf; + bktr->alloc_pages = BROOKTREE_ALLOC_PAGES; + if ( buf != 0 ) { + bzero((caddr_t) buf, BROOKTREE_ALLOC); + buf = vtophys(buf); + bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE | + METEOR_DEV0 | METEOR_RGB16; + bktr->dma_prog_loaded = FALSE; + bktr->cols = 640; + bktr->rows = 480; + bktr->frames = 1; /* one frame */ + bktr->format = METEOR_GEO_RGB16; + bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); + bktr->pixfmt_compat = TRUE; + bt848 = bktr->base; + bt848->int_mask = ALL_INTS_DISABLED; + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + } + + /* defaults for the tuner section of the card */ + bktr->tflags = TUNER_INITALIZED; + bktr->tuner.frequency = 0; + bktr->tuner.channel = 0; + bktr->tuner.chnlset = DEFAULT_CHNLSET; + bktr->audio_mux_select = 0; + bktr->audio_mute_state = FALSE; + probeCard( bktr, TRUE ); + +#ifdef DEVFS + /* XXX This just throw away the token, which should probably be fixed when + DEVFS is finally made really operational. */ + devfs_add_devswf(&bktr_cdevsw, unit, DV_CHR, 0, 0, 0444, "bktr%d", unit); + devfs_add_devswf(&bktr_cdevsw, unit+16, DV_CHR, 0, 0, 0444, "tuner%d", unit); +#endif /* DEVFS */ +#if __FreeBSD__ > 2 + fun = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, fun | 4); +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) + fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, fun | 4); +#endif + +} + + +/* + * interrupt handling routine complete bktr_read() if using interrupts. + */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +static int +#else +static void +#endif +bktr_intr( void *arg ) +{ + bktr_ptr_t bktr; + bt848_ptr_t bt848; + u_long bktr_status; + u_char dstatus; + u_long field; + u_long w_field; + u_long req_field; + + bktr = (bktr_ptr_t) arg; + bt848 = bktr->base; + + /* + * check to see if any interrupts are unmasked on this device. If + * none are, then we likely got here by way of being on a PCI shared + * interrupt dispatch list. + */ + if (bt848->int_mask == ALL_INTS_DISABLED) +#if defined(__NetBSD__) || defined(__OpenBSD__) + return 0; /* bail out now, before we do something we + shouldn't */ +#else + return; /* bail out now, before we do something we + shouldn't */ +#endif + + if (!(bktr->flags & METEOR_OPEN)) { + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + bt848->int_mask = ALL_INTS_DISABLED; + /* return; ?? */ + } + + /* record and clear the INTerrupt status bits */ + bktr_status = bt848->int_stat; + bt848->int_stat = bktr_status & ~I2C_BITS; /* don't touch i2c */ + + /* record and clear the device status register */ + dstatus = bt848->dstatus; + bt848->dstatus = 0x00; + +#if defined( STATUS_SUM ) + /* add any new device status or INTerrupt status bits */ + status_sum |= (bktr_status & ~(BT848_INT_RSV0|BT848_INT_RSV1)); + status_sum |= ((dstatus & (BT848_DSTATUS_COF|BT848_DSTATUS_LOF)) << 6); +#endif /* STATUS_SUM */ + /* printf( " STATUS %x %x %x \n", + dstatus, bktr_status, bt848->risc_count ); + */ + /* if risc was disabled re-start process again */ + if ( !(bktr_status & BT848_INT_RISC_EN) || + ((bktr_status &(BT848_INT_FBUS | + BT848_INT_FTRGT | + BT848_INT_FDSR | + BT848_INT_PPERR | + BT848_INT_RIPERR | + BT848_INT_PABORT | + BT848_INT_OCERR | + BT848_INT_SCERR) ) != 0) || + ((bt848->tdec == 0) && (bktr_status & TDEC_BITS)) ) { + + u_short tdec_save = bt848->tdec; + + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + + bt848->int_mask = ALL_INTS_DISABLED; + + /* Reset temporal decimation ctr */ + bt848->tdec = 0; + bt848->tdec = tdec_save; + + /* Reset to no-fields captured state */ + if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + break; + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + break; + } + } + + bt848->risc_strt_add = vtophys(bktr->dma_prog); + bt848->gpio_dma_ctl = FIFO_ENABLED; + bt848->gpio_dma_ctl = bktr->capcontrol; + + bt848->int_mask = BT848_INT_MYSTERYBIT | + BT848_INT_RISCI | + BT848_INT_VSYNC | + BT848_INT_FMTCHG; + + bt848->cap_ctl = bktr->bktr_cap_ctl; + +#if defined(__NetBSD__) || defined(__OpenBSD__) + return 1; +#else + return; +#endif + } + + if (!(bktr_status & BT848_INT_RISCI)) { +#if defined(__NetBSD__) || defined(__OpenBSD__) + return 0; +#else + return; +#endif + } + /* + printf( "intr status %x %x %x\n", + bktr_status, dstatus, bt848->risc_count ); + */ + + + /* + * Disable future interrupts if a capture mode is not selected. + * This can happen when we are in the process of closing or + * changing capture modes, otherwise it shouldn't happen. + */ + if (!(bktr->flags & METEOR_CAP_MASK)) + bt848->cap_ctl = CAPTURE_OFF; + + /* + * Register the completed field + * (For dual-field mode, require fields from the same frame) + */ + field = ( bktr_status & BT848_INT_FIELD ) ? EVEN_F : ODD_F; + switch ( bktr->flags & METEOR_WANT_MASK ) { + case METEOR_WANT_ODD : w_field = ODD_F ; break; + case METEOR_WANT_EVEN : w_field = EVEN_F ; break; + default : w_field = (ODD_F|EVEN_F); break; + } + switch ( bktr->flags & METEOR_ONLY_FIELDS_MASK ) { + case METEOR_ONLY_ODD_FIELDS : req_field = ODD_F ; break; + case METEOR_ONLY_EVEN_FIELDS : req_field = EVEN_F ; break; + default : req_field = (ODD_F|EVEN_F); + break; + } + + if (( field == EVEN_F ) && ( w_field == EVEN_F )) + bktr->flags &= ~METEOR_WANT_EVEN; + else if (( field == ODD_F ) && ( req_field == ODD_F ) && + ( w_field == ODD_F )) + bktr->flags &= ~METEOR_WANT_ODD; + else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) && + ( w_field == (ODD_F|EVEN_F) )) + bktr->flags &= ~METEOR_WANT_ODD; + else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) && + ( w_field == ODD_F )) { + bktr->flags &= ~METEOR_WANT_ODD; + bktr->flags |= METEOR_WANT_EVEN; + } + else { + /* We're out of sync. Start over. */ + if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + break; + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + break; + } + } +#if defined(__NetBSD__) || defined(__OpenBSD__) + return 1; +#else + return; +#endif + } + + /* + * If we have a complete frame. + */ + if (!(bktr->flags & METEOR_WANT_MASK)) { + bktr->frames_captured++; + /* + * post the completion time. + */ + if (bktr->flags & METEOR_WANT_TS) { + struct timeval *ts; + + if ((u_int) bktr->alloc_pages * PAGE_SIZE + <= (bktr->frame_size + sizeof(struct timeval))) { + ts =(struct timeval *)bktr->bigbuf + + bktr->frame_size; + /* doesn't work in synch mode except + * for first frame */ + /* XXX */ + microtime(ts); + } + } + + /* + * Wake up the user in single capture mode. + */ + if (bktr->flags & METEOR_SINGLE) { + + /* stop dma */ + bt848->int_mask = ALL_INTS_DISABLED; + + /* disable risc, leave fifo running */ + bt848->gpio_dma_ctl = FIFO_ENABLED; + wakeup((caddr_t)bktr); + } + + /* + * If the user requested to be notified via signal, + * let them know the frame is complete. + */ + + if (bktr->proc && !(bktr->signal & METEOR_SIG_MODE_MASK)) + psignal( bktr->proc, + bktr->signal&(~METEOR_SIG_MODE_MASK) ); + + /* + * Reset the want flags if in continuous or + * synchronous capture mode. + */ +/* +* XXX NOTE (Luigi): +* currently we only support 3 capture modes: odd only, even only, +* odd+even interlaced (odd field first). A fourth mode (non interlaced, +* either even OR odd) could provide 60 (50 for PAL) pictures per +* second, but it would require this routine to toggle the desired frame +* each time, and one more different DMA program for the Bt848. +* As a consequence, this fourth mode is currently unsupported. +*/ + + if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + break; + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + break; + } + } + } + +#if defined(__NetBSD__) || defined(__OpenBSD__) + return 1; +#else + return; +#endif +} + + +/*--------------------------------------------------------- +** +** BrookTree 848 character device driver routines +** +**--------------------------------------------------------- +*/ + + +#define VIDEO_DEV 0x00 +#define TUNER_DEV 0x01 + +/* + * + */ +int +bktr_open( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_ptr_t bktr; + int unit; + + unit = UNIT( minor(dev) ); + if (unit >= NBKTR) /* unit out of range */ + return( ENXIO ); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + bktr = bktr_cd.cd_devs[unit]; +#else + bktr = &(brooktree[ unit ]); +#endif + + if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */ + return( ENXIO ); + + switch ( MINOR( minor(dev) ) ) { + case VIDEO_DEV: + return( video_open( bktr ) ); + + case TUNER_DEV: + return( tuner_open( bktr ) ); + } + + return( ENXIO ); +} + + +/* + * + */ +static int +video_open( bktr_ptr_t bktr ) +{ + bt848_ptr_t bt848; + + if (bktr->flags & METEOR_OPEN) /* device is busy */ + return( EBUSY ); + + bktr->flags |= METEOR_OPEN; + + bt848 = bktr->base; + +#ifdef BT848_DUMP + dump_bt848( bt848 ); +#endif + + bt848->dstatus = 0x00; /* clear device status reg. */ + + bt848->adc = SYNC_LEVEL; + + bt848->iform = BT848_IFORM_M_MUX1 | + BT848_IFORM_X_XT0 | + BT848_IFORM_F_NTSCM; + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0; + bktr->format_params = BT848_IFORM_F_NTSCM; + + bktr->max_clip_node = 0; + +#ifndef ORIGINAL + bt848->color_ctl_gamma = 1; +#else + bt848->color_ctl_gamma = 0; +#endif + bt848->color_ctl_rgb_ded = 1; + bt848->color_ctl_color_bars = 0; + bt848->color_ctl_ext_frmrate = 0; + bt848->color_ctl_swap = 0; + + bt848->e_hscale_lo = 170; + bt848->o_hscale_lo = 170; + + bt848->e_delay_lo = 0x72; + bt848->o_delay_lo = 0x72; + bt848->e_scloop = 0; + bt848->o_scloop = 0; + + bt848->vbi_pack_size = 0; + bt848->vbi_pack_del = 0; + + bktr->fifo_errors = 0; + bktr->dma_errors = 0; + bktr->frames_captured = 0; + bktr->even_fields_captured = 0; + bktr->odd_fields_captured = 0; + bktr->proc = (struct proc *)0; + set_fps(bktr, 30); + bktr->video.addr = 0; + bktr->video.width = 0; + bktr->video.banksize = 0; + bktr->video.ramsize = 0; + bktr->pixfmt_compat = TRUE; + bktr->format = METEOR_GEO_RGB16; + bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); + + + bt848->int_mask = BT848_INT_MYSTERYBIT; /* what does this bit do ??? */ + + /* wait 2 seconds while bt848 initialises */ + tsleep( (caddr_t)bktr, PZERO, "btinit", hz*2 ); + + return( 0 ); +} + + +/* + * + */ +static int +tuner_open( bktr_ptr_t bktr ) +{ + if ( !(bktr->tflags & TUNER_INITALIZED) ) /* device not found */ + return( ENXIO ); + + if ( bktr->tflags & TUNER_OPEN ) /* already open */ + return( 0 ); + + bktr->tflags |= TUNER_OPEN; + bktr->tuner.radio_mode = 0; + + /* enable drivers on the GPIO port that control the MUXes */ + bktr->base->gpio_out_en = GPIO_AUDIOMUX_BITS; + + /* unmute the audio stream */ + set_audio( bktr, AUDIO_UNMUTE ); + + /* enable stereo if appropriate */ + if ( bktr->card.dbx ) + set_BTSC( bktr, 0 ); + + return( 0 ); +} + + +/* + * + */ +int +bktr_close( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_ptr_t bktr; + int unit; + + unit = UNIT( minor(dev) ); + if (unit >= NBKTR) /* unit out of range */ + return( ENXIO ); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + bktr = bktr_cd.cd_devs[unit]; +#else + bktr = &(brooktree[ unit ]); +#endif + + switch ( MINOR( minor(dev) ) ) { + case VIDEO_DEV: + return( video_close( bktr ) ); + + case TUNER_DEV: + return( tuner_close( bktr ) ); + } + + return( ENXIO ); +} + + +/* + * + */ +static int +video_close( bktr_ptr_t bktr ) +{ + bt848_ptr_t bt848; + + bktr->flags &= ~(METEOR_OPEN | + METEOR_SINGLE | + METEOR_CAP_MASK | + METEOR_WANT_MASK); + + bt848 = bktr->base; + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + bt848->cap_ctl = CAPTURE_OFF; + + bktr->dma_prog_loaded = FALSE; + bt848->tdec = 0; + bt848->int_mask = ALL_INTS_DISABLED; + +/** FIXME: is 0xf magic, wouldn't 0x00 work ??? */ + bt848->sreset = 0xf; + bt848->int_stat = ALL_INTS_CLEARED; + + return( 0 ); +} + + +/* + * tuner close handle, + * place holder for tuner specific operations on a close. + */ +static int +tuner_close( bktr_ptr_t bktr ) +{ + bktr->tflags &= ~TUNER_OPEN; + + /* mute the audio by switching the mux */ + set_audio( bktr, AUDIO_MUTE ); + + /* disable drivers on the GPIO port that control the MUXes */ + bktr->base->gpio_out_en = 0; + + return( 0 ); +} + + +/* + * + */ +int +bktr_read( dev_t dev, struct uio *uio, int ioflag ) +{ + bktr_ptr_t bktr; + bt848_ptr_t bt848; + int unit; + int status; + int count; + + if (MINOR(minor(dev)) > 0) + return( ENXIO ); + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return( ENXIO ); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + bktr = bktr_cd.cd_devs[unit]; +#else + bktr = &(brooktree[unit]); +#endif + bt848 = bktr->base; + + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return( ENOMEM ); + + if (bktr->flags & METEOR_CAP_MASK) + return( EIO ); /* already capturing */ + + bt848->cap_ctl = bktr->bktr_cap_ctl; + + + count = bktr->rows * bktr->cols * + pixfmt_table[ bktr->pixfmt ].public.Bpp; + + if ((int) uio->uio_iov->iov_len < count) + return( EINVAL ); + + bktr->flags &= ~(METEOR_CAP_MASK | METEOR_WANT_MASK); + + /* capture one frame */ + start_capture(bktr, METEOR_SINGLE); + /* wait for capture to complete */ + bt848->int_stat = ALL_INTS_CLEARED; + bt848->gpio_dma_ctl = FIFO_ENABLED; + bt848->gpio_dma_ctl = bktr->capcontrol; + bt848->int_mask = BT848_INT_MYSTERYBIT | + BT848_INT_RISCI | + BT848_INT_VSYNC | + BT848_INT_FMTCHG; + + + status = tsleep((caddr_t)bktr, BKTRPRI, "captur", 0); + if (!status) /* successful capture */ + status = uiomove((caddr_t)bktr->bigbuf, count, uio); + else + printf ("bktr%d: read: tsleep error %d\n", unit, status); + + bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); + + return( status ); +} + + +/* + * + */ +int +bktr_write( dev_t dev, struct uio *uio, int ioflag ) +{ + return( EINVAL ); /* XXX or ENXIO ? */ +} + + +/* + * + */ +int +bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr ) +{ + bktr_ptr_t bktr; + int unit; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return( ENXIO ); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + bktr = bktr_cd.cd_devs[unit]; +#else + bktr = &(brooktree[ unit ]); +#endif + + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return( ENOMEM ); + + switch ( MINOR( minor(dev) ) ) { + case VIDEO_DEV: + return( video_ioctl( bktr, unit, cmd, arg, pr ) ); + + case TUNER_DEV: + return( tuner_ioctl( bktr, unit, cmd, arg, pr ) ); + } + + return( ENXIO ); +} + + +/* + * video ioctls + */ +static int +video_ioctl( bktr_ptr_t bktr, int unit, int cmd, caddr_t arg, struct proc* pr ) +{ + bt848_ptr_t bt848; + volatile u_char c_temp; + unsigned int temp; + unsigned int temp_iform; + unsigned int error; + struct meteor_geomet *geo; +#if defined(__NetBSD__) || defined(__OpenBSD__) + struct meteor_counts *count; +#else + struct meteor_counts *cnt; +#endif + struct meteor_video *video; + vm_offset_t buf; +#if !defined(__NetBSD__) && !defined(__OpenBSD__) + struct format_params *fp; + int tmp_int; +#endif + int i; + + bt848 = bktr->base; + + switch ( cmd ) { + + case BT848SCLIP: /* set clip region */ + bktr->max_clip_node = 0; + memcpy(&bktr->clip_list, arg, sizeof(bktr->clip_list)); + + for (i = 0; i < BT848_MAX_CLIP_NODE; i++) { + if (bktr->clip_list[i].y_min == 0 && + bktr->clip_list[i].y_max == 0) + break; + } + bktr->max_clip_node = i; + + /* make sure that the list contains a valid clip secquence */ + /* the clip rectangles should be sorted by x then by y as the + second order sort key */ + + /* clip rectangle list is terminated by y_min and y_max set to 0 */ + + /* to disable clipping set y_min and y_max to 0 in the first + clip rectangle . The first clip rectangle is clip_list[0]. + */ + + + + if (bktr->max_clip_node == 0 && + (bktr->clip_list[0].y_min != 0 && + bktr->clip_list[0].y_max != 0)) { + return EINVAL; + } + + for (i = 0; i < BT848_MAX_CLIP_NODE - 1 ; i++) { + if (bktr->clip_list[i].y_min == 0 && + bktr->clip_list[i].y_max == 0) { + break; + } + if ( bktr->clip_list[i+1].y_min != 0 && + bktr->clip_list[i+1].y_max != 0 && + bktr->clip_list[i].x_min > bktr->clip_list[i+1].x_min ) { + + bktr->max_clip_node = 0; + return (EINVAL); + + } + + if (bktr->clip_list[i].x_min >= bktr->clip_list[i].x_max || + bktr->clip_list[i].y_min >= bktr->clip_list[i].y_max || + bktr->clip_list[i].x_min < 0 || + bktr->clip_list[i].x_max < 0 || + bktr->clip_list[i].y_min < 0 || + bktr->clip_list[i].y_max < 0 ) { + bktr->max_clip_node = 0; + return (EINVAL); + } + } + + bktr->dma_prog_loaded = FALSE; + + break; + + case METEORSTATUS: /* get Bt848 status */ + c_temp = bt848->dstatus; + temp = 0; + if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK; + if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT; + *(u_short *)arg = temp; + break; + + case BT848SFMT: /* set input format */ + temp = *(unsigned long*)arg & BT848_IFORM_FORMAT; + temp_iform = bt848->iform; + temp_iform &= ~BT848_IFORM_FORMAT; + temp_iform &= ~BT848_IFORM_XTSEL; + bt848->iform = (temp_iform | temp | format_params[temp].iform_xtsel); + switch( temp ) { + case BT848_IFORM_F_AUTO: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_AUTOMODE; + break; + + case BT848_IFORM_F_NTSCM: + case BT848_IFORM_F_NTSCJ: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_NTSC; + bt848->adelay = format_params[temp].adelay; + bt848->bdelay = format_params[temp].bdelay; + bktr->format_params = temp; + break; + + case BT848_IFORM_F_PALBDGHI: + case BT848_IFORM_F_PALN: + case BT848_IFORM_F_SECAM: + case BT848_IFORM_F_RSVD: + case BT848_IFORM_F_PALM: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_PAL; + bt848->adelay = format_params[temp].adelay; + bt848->bdelay = format_params[temp].bdelay; + bktr->format_params = temp; + break; + + } + bktr->dma_prog_loaded = FALSE; + break; + + case METEORSFMT: /* set input format */ + temp_iform = bt848->iform; + temp_iform &= ~BT848_IFORM_FORMAT; + temp_iform &= ~BT848_IFORM_XTSEL; + switch(*(unsigned long *)arg & METEOR_FORM_MASK ) { + case 0: /* default */ + case METEOR_FMT_NTSC: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_NTSC; + bt848->iform = temp_iform | BT848_IFORM_F_NTSCM | + format_params[BT848_IFORM_F_NTSCM].iform_xtsel; + bt848->adelay = format_params[BT848_IFORM_F_NTSCM].adelay; + bt848->bdelay = format_params[BT848_IFORM_F_NTSCM].bdelay; + bktr->format_params = BT848_IFORM_F_NTSCM; + break; + + case METEOR_FMT_PAL: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_PAL; + bt848->iform = temp_iform | BT848_IFORM_F_PALBDGHI | + format_params[BT848_IFORM_F_PALBDGHI].iform_xtsel; + bt848->adelay = format_params[BT848_IFORM_F_PALBDGHI].adelay; + bt848->bdelay = format_params[BT848_IFORM_F_PALBDGHI].bdelay; + bktr->format_params = BT848_IFORM_F_PALBDGHI; + break; + + case METEOR_FMT_AUTOMODE: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_AUTOMODE; + bt848->iform = temp_iform | BT848_IFORM_F_AUTO | + format_params[BT848_IFORM_F_AUTO].iform_xtsel; + break; + + default: + return( EINVAL ); + } + bktr->dma_prog_loaded = FALSE; + break; + + case METEORGFMT: /* get input format */ + *(u_long *)arg = bktr->flags & METEOR_FORM_MASK; + break; + + + case BT848GFMT: /* get input format */ + *(u_long *)arg = bt848->iform & BT848_IFORM_FORMAT; + break; + + case METEORSCOUNT: /* (re)set error counts */ +#if defined(__NetBSD__) || defined(__OpenBSD__) + count = (struct meteor_counts *) arg; + bktr->fifo_errors = count->fifo_errors; + bktr->dma_errors = count->dma_errors; + bktr->frames_captured = count->frames_captured; + bktr->even_fields_captured = count->even_fields_captured; + bktr->odd_fields_captured = count->odd_fields_captured; +#else + cnt = (struct meteor_counts *) arg; + bktr->fifo_errors = cnt->fifo_errors; + bktr->dma_errors = cnt->dma_errors; + bktr->frames_captured = cnt->frames_captured; + bktr->even_fields_captured = cnt->even_fields_captured; + bktr->odd_fields_captured = cnt->odd_fields_captured; +#endif + break; + + case METEORGCOUNT: /* get error counts */ +#if defined(__NetBSD__) || defined(__OpenBSD__) + count = (struct meteor_counts *) arg; + count->fifo_errors = bktr->fifo_errors; + count->dma_errors = bktr->dma_errors; + count->frames_captured = bktr->frames_captured; + count->even_fields_captured = bktr->even_fields_captured; + count->odd_fields_captured = bktr->odd_fields_captured; +#else + cnt = (struct meteor_counts *) arg; + cnt->fifo_errors = bktr->fifo_errors; + cnt->dma_errors = bktr->dma_errors; + cnt->frames_captured = bktr->frames_captured; + cnt->even_fields_captured = bktr->even_fields_captured; + cnt->odd_fields_captured = bktr->odd_fields_captured; +#endif + break; + + case METEORGVIDEO: + video = (struct meteor_video *)arg; + video->addr = bktr->video.addr; + video->width = bktr->video.width; + video->banksize = bktr->video.banksize; + video->ramsize = bktr->video.ramsize; + break; + + case METEORSVIDEO: + video = (struct meteor_video *)arg; + bktr->video.addr = video->addr; + bktr->video.width = video->width; + bktr->video.banksize = video->banksize; + bktr->video.ramsize = video->ramsize; + break; + + case METEORSFPS: + set_fps(bktr, *(u_short *)arg); + break; + + case METEORGFPS: + *(u_short *)arg = bktr->fps; + break; + + case METEORSHUE: /* set hue */ + bt848->hue = (*(u_char *) arg) & 0xff; + break; + + case METEORGHUE: /* get hue */ + *(u_char *)arg = bt848->hue; + break; + + case METEORSBRIG: /* set brightness */ + bt848->bright = *(u_char *)arg & 0xff; + break; + + case METEORGBRIG: /* get brightness */ + *(u_char *)arg = bt848->bright; + break; + + case METEORSCSAT: /* set chroma saturation */ + temp = (int)*(u_char *)arg; + + bt848->sat_u_lo = bt848->sat_v_lo = (temp << 1) & 0xff; + + bt848->e_control &= ~(BT848_E_CONTROL_SAT_U_MSB | + BT848_E_CONTROL_SAT_V_MSB); + bt848->o_control &= ~(BT848_O_CONTROL_SAT_U_MSB | + BT848_O_CONTROL_SAT_V_MSB); + + if ( temp & BIT_SEVEN_HIGH ) { + bt848->e_control |= (BT848_E_CONTROL_SAT_U_MSB | + BT848_E_CONTROL_SAT_V_MSB); + bt848->o_control |= (BT848_O_CONTROL_SAT_U_MSB | + BT848_O_CONTROL_SAT_V_MSB); + } + break; + + case METEORGCSAT: /* get chroma saturation */ + temp = (bt848->sat_v_lo >> 1) & 0xff; + if ( bt848->e_control & BT848_E_CONTROL_SAT_V_MSB ) + temp |= BIT_SEVEN_HIGH; + *(u_char *)arg = (u_char)temp; + break; + + case METEORSCONT: /* set contrast */ + temp = (int)*(u_char *)arg & 0xff; + temp <<= 1; + bt848->contrast_lo = temp & 0xff; + bt848->e_control &= ~BT848_E_CONTROL_CON_MSB; + bt848->o_control &= ~BT848_O_CONTROL_CON_MSB; + bt848->e_control |= + ((temp & 0x100) >> 6 ) & BT848_E_CONTROL_CON_MSB; + bt848->o_control |= + ((temp & 0x100) >> 6 ) & BT848_O_CONTROL_CON_MSB; + break; + + case METEORGCONT: /* get contrast */ + temp = (int)bt848->contrast_lo & 0xff; + temp |= ((int)bt848->o_control & 0x04) << 6; + *(u_char *)arg = (u_char)((temp >> 1) & 0xff); + break; + + case METEORSSIGNAL: + if(*(int *)arg == 0 || *(int *)arg >= NSIG) { + return( EINVAL ); + break; + } + bktr->signal = *(int *) arg; + bktr->proc = pr; + break; + + case METEORGSIGNAL: + *(int *)arg = bktr->signal; + break; + + case METEORCAPTUR: + temp = bktr->flags; + switch (*(int *) arg) { + case METEOR_CAP_SINGLE: + + if (bktr->bigbuf==0) /* no frame buffer allocated */ + return( ENOMEM ); + /* already capturing */ + if (temp & METEOR_CAP_MASK) + return( EIO ); + + + + start_capture(bktr, METEOR_SINGLE); + + /* wait for capture to complete */ + bt848->int_stat = ALL_INTS_CLEARED; + bt848->gpio_dma_ctl = FIFO_ENABLED; + bt848->gpio_dma_ctl = bktr->capcontrol; + + bt848->int_mask = BT848_INT_MYSTERYBIT | + BT848_INT_RISCI | + BT848_INT_VSYNC | + BT848_INT_FMTCHG; + + bt848->cap_ctl = bktr->bktr_cap_ctl; + error = tsleep((caddr_t)bktr, BKTRPRI, "captur", hz); + if (error && (error != ERESTART)) { + /* Here if we didn't get complete frame */ +#ifdef DIAGNOSTIC + printf( "bktr%d: ioctl: tsleep error %d %x\n", + unit, error, bt848->risc_count); +#endif + + /* stop dma */ + bt848->int_mask = ALL_INTS_DISABLED; + + /* disable risc, leave fifo running */ + bt848->gpio_dma_ctl = FIFO_ENABLED; + } + + bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK); + /* FIXME: should we set bt848->int_stat ??? */ + break; + + case METEOR_CAP_CONTINOUS: + if (bktr->bigbuf==0) /* no frame buffer allocated */ + return( ENOMEM ); + /* already capturing */ + if (temp & METEOR_CAP_MASK) + return( EIO ); + + + start_capture(bktr, METEOR_CONTIN); + bt848->int_stat = bt848->int_stat; + + bt848->gpio_dma_ctl = FIFO_ENABLED; + bt848->gpio_dma_ctl = bktr->capcontrol; + bt848->cap_ctl = bktr->bktr_cap_ctl; + + bt848->int_mask = BT848_INT_MYSTERYBIT | + BT848_INT_RISCI | + BT848_INT_VSYNC | + BT848_INT_FMTCHG; +#ifdef BT848_DUMP + dump_bt848( bt848 ); +#endif + break; + + case METEOR_CAP_STOP_CONT: + if (bktr->flags & METEOR_CONTIN) { + /* turn off capture */ + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + bt848->cap_ctl = CAPTURE_OFF; + bt848->int_mask = ALL_INTS_DISABLED; + bktr->flags &= + ~(METEOR_CONTIN | METEOR_WANT_MASK); + + } + } + break; + + case METEORSETGEO: + /* can't change parameters while capturing */ + if (bktr->flags & METEOR_CAP_MASK) + return( EBUSY ); + + + geo = (struct meteor_geomet *) arg; + + error = 0; + /* Either even or odd, if even & odd, then these a zero */ + if ((geo->oformat & METEOR_GEO_ODD_ONLY) && + (geo->oformat & METEOR_GEO_EVEN_ONLY)) { + printf( "bktr%d: ioctl: Geometry odd or even only.\n", + unit); + return( EINVAL ); + } + + /* set/clear even/odd flags */ + if (geo->oformat & METEOR_GEO_ODD_ONLY) + bktr->flags |= METEOR_ONLY_ODD_FIELDS; + else + bktr->flags &= ~METEOR_ONLY_ODD_FIELDS; + if (geo->oformat & METEOR_GEO_EVEN_ONLY) + bktr->flags |= METEOR_ONLY_EVEN_FIELDS; + else + bktr->flags &= ~METEOR_ONLY_EVEN_FIELDS; + + if ((geo->columns & 0x3fe) != geo->columns) { + printf( + "bktr%d: ioctl: %d: columns too large or not even.\n", + unit, geo->columns); + error = EINVAL; + } + if (((geo->rows & 0x7fe) != geo->rows) || + ((geo->oformat & METEOR_GEO_FIELD_MASK) && + ((geo->rows & 0x3fe) != geo->rows)) ) { + printf( + "bktr%d: ioctl: %d: rows too large or not even.\n", + unit, geo->rows); + error = EINVAL; + } + if (geo->frames > 32) { + printf("bktr%d: ioctl: too many frames.\n", unit); + + error = EINVAL; + } + + if (error) + return( error ); + + bktr->dma_prog_loaded = FALSE; + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + + bt848->int_mask = ALL_INTS_DISABLED; + + if ((temp=(geo->rows * geo->columns * geo->frames * 2))) { + if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2; + + /* meteor_mem structure for SYNC Capture */ + if (geo->frames > 1) temp += PAGE_SIZE; + + temp = btoc(temp); + if ((int) temp > bktr->alloc_pages + && bktr->video.addr == 0) { +#if defined(__NetBSD__) || defined(__OpenBSD__) + bus_dmamap_t dmamap; + + buf = get_bktr_mem(bktr, &dmamap, + temp * PAGE_SIZE); +#else + buf = get_bktr_mem(unit, temp*PAGE_SIZE); +#endif + if (buf != 0) { +#if defined(__NetBSD__) || defined(__OpenBSD__) + free_bktr_mem(bktr, bktr->dm_mem, + bktr->bigbuf); + bktr->dm_mem = dmamap; +#else + kmem_free(kernel_map, bktr->bigbuf, + (bktr->alloc_pages * PAGE_SIZE)); +#endif + bktr->bigbuf = buf; + bktr->alloc_pages = temp; + if (bootverbose) + printf( + "bktr%d: ioctl: Allocating %d bytes\n", + unit, temp*PAGE_SIZE); + } + else + error = ENOMEM; + } + } + + if (error) + return error; + + bktr->rows = geo->rows; + bktr->cols = geo->columns; + bktr->frames = geo->frames; + + /* Pixel format (if in meteor pixfmt compatibility mode) */ + if ( bktr->pixfmt_compat ) { + bktr->format = METEOR_GEO_YUV_422; + switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) { + case 0: /* default */ + case METEOR_GEO_RGB16: + bktr->format = METEOR_GEO_RGB16; + break; + case METEOR_GEO_RGB24: + bktr->format = METEOR_GEO_RGB24; + break; + case METEOR_GEO_YUV_422: + bktr->format = METEOR_GEO_YUV_422; + if (geo->oformat & METEOR_GEO_YUV_12) + bktr->format = METEOR_GEO_YUV_12; + break; + case METEOR_GEO_YUV_PACKED: + bktr->format = METEOR_GEO_YUV_PACKED; + break; + } + bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); + } + + if (bktr->flags & METEOR_CAP_MASK) { + + if (bktr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) { + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + break; + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + break; + } + + start_capture(bktr, METEOR_CONTIN); + bt848->int_stat = bt848->int_stat; + bt848->gpio_dma_ctl = FIFO_ENABLED; + bt848->gpio_dma_ctl = bktr->capcontrol; + bt848->int_mask = BT848_INT_MYSTERYBIT | + BT848_INT_VSYNC | + BT848_INT_FMTCHG; + } + } + break; + /* end of METEORSETGEO */ + + default: + return common_ioctl( bktr, bt848, cmd, arg ); + } + + return( 0 ); +} + +/* + * tuner ioctls + */ +static int +tuner_ioctl( bktr_ptr_t bktr, int unit, int cmd, caddr_t arg, struct proc* pr ) +{ + bt848_ptr_t bt848; + int tmp_int; + unsigned int temp, temp1; + int offset; + int count; + u_char *buf; + u_long par; + u_char write; + int i2c_addr; + int i2c_port; + u_long data; + + bt848 = bktr->base; + + switch ( cmd ) { + +#if defined( TUNER_AFC ) + case TVTUNER_SETAFC: + bktr->tuner.afc = (*(int *)arg != 0); + break; + + case TVTUNER_GETAFC: + *(int *)arg = bktr->tuner.afc; + /* XXX Perhaps use another bit to indicate AFC success? */ + break; +#endif /* TUNER_AFC */ + + case TVTUNER_SETCHNL: + temp_mute( bktr, TRUE ); + temp = tv_channel( bktr, (int)*(unsigned long *)arg ); + temp_mute( bktr, FALSE ); + if ( temp < 0 ) + return( EINVAL ); + *(unsigned long *)arg = temp; + break; + + case TVTUNER_GETCHNL: + *(unsigned long *)arg = bktr->tuner.channel; + break; + + case TVTUNER_SETTYPE: + temp = *(unsigned long *)arg; + if ( (temp < CHNLSET_MIN) || (temp > CHNLSET_MAX) ) + return( EINVAL ); + bktr->tuner.chnlset = temp; + break; + + case TVTUNER_GETTYPE: + *(unsigned long *)arg = bktr->tuner.chnlset; + break; + + case TVTUNER_GETSTATUS: + temp = i2cRead( bktr, TSA552x_RADDR ); + *(unsigned long *)arg = temp & 0xff; + break; + + case TVTUNER_SETFREQ: + temp_mute( bktr, TRUE ); + temp = tv_freq( bktr, (int)*(unsigned long *)arg ); + temp_mute( bktr, FALSE ); + if ( temp < 0 ) + return( EINVAL ); + *(unsigned long *)arg = temp; + break; + + case TVTUNER_GETFREQ: + *(unsigned long *)arg = bktr->tuner.frequency; + break; + + case BT848_SAUDIO: /* set audio channel */ + if ( set_audio( bktr, *(int*)arg ) < 0 ) + return( EIO ); + break; + + /* hue is a 2's compliment number, -90' to +89.3' in 0.7' steps */ + case BT848_SHUE: /* set hue */ + bt848->hue = (u_char)(*(int*)arg & 0xff); + break; + + case BT848_GHUE: /* get hue */ + *(int*)arg = (signed char)(bt848->hue & 0xff); + break; + + /* brightness is a 2's compliment #, -50 to +%49.6% in 0.39% steps */ + case BT848_SBRIG: /* set brightness */ + bt848->bright = (u_char)(*(int *)arg & 0xff); + break; + + case BT848_GBRIG: /* get brightness */ + *(int *)arg = (signed char)(bt848->bright & 0xff); + break; + + /* */ + case BT848_SCSAT: /* set chroma saturation */ + tmp_int = *(int*)arg; + + temp = bt848->e_control; + temp1 = bt848->o_control; + if ( tmp_int & BIT_EIGHT_HIGH ) { + temp |= (BT848_E_CONTROL_SAT_U_MSB | + BT848_E_CONTROL_SAT_V_MSB); + temp1 |= (BT848_O_CONTROL_SAT_U_MSB | + BT848_O_CONTROL_SAT_V_MSB); + } + else { + temp &= ~(BT848_E_CONTROL_SAT_U_MSB | + BT848_E_CONTROL_SAT_V_MSB); + temp1 &= ~(BT848_O_CONTROL_SAT_U_MSB | + BT848_O_CONTROL_SAT_V_MSB); + } + + bt848->sat_u_lo = (u_char)(tmp_int & 0xff); + bt848->sat_v_lo = (u_char)(tmp_int & 0xff); + bt848->e_control = temp; + bt848->o_control = temp1; + break; + + case BT848_GCSAT: /* get chroma saturation */ + tmp_int = (int)(bt848->sat_v_lo & 0xff); + if ( bt848->e_control & BT848_E_CONTROL_SAT_V_MSB ) + tmp_int |= BIT_EIGHT_HIGH; + *(int*)arg = tmp_int; + break; + + /* */ + case BT848_SVSAT: /* set chroma V saturation */ + tmp_int = *(int*)arg; + + temp = bt848->e_control; + temp1 = bt848->o_control; + if ( tmp_int & BIT_EIGHT_HIGH) { + temp |= BT848_E_CONTROL_SAT_V_MSB; + temp1 |= BT848_O_CONTROL_SAT_V_MSB; + } + else { + temp &= ~BT848_E_CONTROL_SAT_V_MSB; + temp1 &= ~BT848_O_CONTROL_SAT_V_MSB; + } + + bt848->sat_v_lo = (u_char)(tmp_int & 0xff); + bt848->e_control = temp; + bt848->o_control = temp1; + break; + + case BT848_GVSAT: /* get chroma V saturation */ + tmp_int = (int)bt848->sat_v_lo & 0xff; + if ( bt848->e_control & BT848_E_CONTROL_SAT_V_MSB ) + tmp_int |= BIT_EIGHT_HIGH; + *(int*)arg = tmp_int; + break; + + /* */ + case BT848_SUSAT: /* set chroma U saturation */ + tmp_int = *(int*)arg; + + temp = bt848->e_control; + temp1 = bt848->o_control; + if ( tmp_int & BIT_EIGHT_HIGH ) { + temp |= BT848_E_CONTROL_SAT_U_MSB; + temp1 |= BT848_O_CONTROL_SAT_U_MSB; + } + else { + temp &= ~BT848_E_CONTROL_SAT_U_MSB; + temp1 &= ~BT848_O_CONTROL_SAT_U_MSB; + } + + bt848->sat_u_lo = (u_char)(tmp_int & 0xff); + bt848->e_control = temp; + bt848->o_control = temp1; + break; + + case BT848_GUSAT: /* get chroma U saturation */ + tmp_int = (int)bt848->sat_u_lo & 0xff; + if ( bt848->e_control & BT848_E_CONTROL_SAT_U_MSB ) + tmp_int |= BIT_EIGHT_HIGH; + *(int*)arg = tmp_int; + break; + +/* lr 970528 luma notch etc - 3 high bits of e_control/o_control */ + + case BT848_SLNOTCH: /* set luma notch */ + tmp_int = (*(int *)arg & 0x7) << 5 ; + bt848->e_control &= ~0xe0 ; + bt848->o_control &= ~0xe0 ; + bt848->e_control |= tmp_int ; + bt848->o_control |= tmp_int ; + break; + + case BT848_GLNOTCH: /* get luma notch */ + *(int *)arg = (int) ( (bt848->e_control & 0xe0) >> 5) ; + break; + + + /* */ + case BT848_SCONT: /* set contrast */ + tmp_int = *(int*)arg; + + temp = bt848->e_control; + temp1 = bt848->o_control; + if ( tmp_int & BIT_EIGHT_HIGH ) { + temp |= BT848_E_CONTROL_CON_MSB; + temp1 |= BT848_O_CONTROL_CON_MSB; + } + else { + temp &= ~BT848_E_CONTROL_CON_MSB; + temp1 &= ~BT848_O_CONTROL_CON_MSB; + } + + bt848->contrast_lo = (u_char)(tmp_int & 0xff); + bt848->e_control = temp; + bt848->o_control = temp1; + break; + + case BT848_GCONT: /* get contrast */ + tmp_int = (int)bt848->contrast_lo & 0xff; + if ( bt848->e_control & BT848_E_CONTROL_CON_MSB ) + tmp_int |= BIT_EIGHT_HIGH; + *(int*)arg = tmp_int; + break; + + /* FIXME: SCBARS and CCBARS require a valid int * */ + /* argument to succeed, but its not used; consider */ + /* using the arg to store the on/off state so */ + /* there's only one ioctl() needed to turn cbars on/off */ + case BT848_SCBARS: /* set colorbar output */ + bt848->color_ctl_color_bars = 1; + break; + + case BT848_CCBARS: /* clear colorbar output */ + bt848->color_ctl_color_bars = 0; + break; + + case BT848_GAUDIO: /* get audio channel */ + temp = bktr->audio_mux_select; + if ( bktr->audio_mute_state == TRUE ) + temp |= AUDIO_MUTE; + *(int*)arg = temp; + break; + + case BT848_SBTSC: /* set audio channel */ + if ( set_BTSC( bktr, *(int*)arg ) < 0 ) + return( EIO ); + break; + + case BT848_WEEPROM: /* write eeprom */ + offset = (((struct eeProm *)arg)->offset); + count = (((struct eeProm *)arg)->count); + buf = &(((struct eeProm *)arg)->bytes[ 0 ]); + if ( writeEEProm( bktr, offset, count, buf ) < 0 ) + return( EIO ); + break; + + case BT848_REEPROM: /* read eeprom */ + offset = (((struct eeProm *)arg)->offset); + count = (((struct eeProm *)arg)->count); + buf = &(((struct eeProm *)arg)->bytes[ 0 ]); + if ( readEEProm( bktr, offset, count, buf ) < 0 ) + return( EIO ); + break; + + case BT848_SIGNATURE: + offset = (((struct eeProm *)arg)->offset); + count = (((struct eeProm *)arg)->count); + buf = &(((struct eeProm *)arg)->bytes[ 0 ]); + if ( signCard( bktr, offset, count, buf ) < 0 ) + return( EIO ); + break; + /* Ioctl's for running the tuner device in radio mode */ + + case RADIO_GETMODE: + *(unsigned char *)arg = bktr->tuner.radio_mode; + break; + + case RADIO_SETMODE: + bktr->tuner.radio_mode = *(unsigned char *)arg; + break; + + case RADIO_GETFREQ: + *(unsigned long *)arg = (bktr->tuner.frequency+407)*5; + break; + + case RADIO_SETFREQ: + /* The argument to this ioctl is NOT freq*16. It is + ** freq*100. + */ + + /* The radio in my stereo and the linear regression function + ** in my HP48 have reached the conclusion that in order to + ** set the radio tuner of the FM1216 to f MHz, the value to + ** enter into the PLL is: f*20-407 + ** If anyone has the exact values from the spec. sheet + ** please forward them -- fj@login.dknet.dk + */ + temp=(int)*(unsigned long *)arg/5-407 +RADIO_OFFSET; + +#ifdef BKTR_RADIO_DEBUG + printf("bktr%d: arg=%d temp=%d\n",unit,(int)*(unsigned long *)arg,temp); +#endif + +#ifndef BKTR_RADIO_NOFREQCHECK + /* According to the spec. sheet the band: 87.5MHz-108MHz */ + /* is supported. */ + if(temp<1343+RADIO_OFFSET || temp>1753+RADIO_OFFSET) { + printf("bktr%d: Radio frequency out of range\n",unit); + return(EINVAL); + } +#endif + temp_mute( bktr, TRUE ); + temp = tv_freq( bktr, temp ); + temp_mute( bktr, FALSE ); +#ifdef BKTR_RADIO_DEBUG + if(temp) + printf("bktr%d: tv_freq returned: %d\n",unit,temp); +#endif + if ( temp < 0 ) + return( EINVAL ); + *(unsigned long *)arg = temp; + break; + /* Luigi's I2CWR ioctl */ + case BT848_I2CWR: + par = *(u_long *)arg; + write = (par >> 24) & 0xff ; + i2c_addr = (par >> 16) & 0xff ; + i2c_port = (par >> 8) & 0xff ; + data = (par) & 0xff ; + + if (write) { + i2cWrite( bktr, i2c_addr, i2c_port, data); + } else { + data = i2cRead( bktr, i2c_addr); + } + *(u_long *)arg = (par & 0xffffff00) | ( data & 0xff ); + break; + + + default: + return common_ioctl( bktr, bt848, cmd, arg ); + } + + return( 0 ); +} + + +/* + * common ioctls + */ +int +common_ioctl( bktr_ptr_t bktr, bt848_ptr_t bt848, int cmd, caddr_t arg ) +{ + int pixfmt; + unsigned int temp; + struct meteor_pixfmt *pf_pub; + + switch (cmd) { + + case METEORSINPUT: /* set input device */ + switch(*(unsigned long *)arg & METEOR_DEV_MASK) { + + /* this is the RCA video input */ + case 0: /* default */ + case METEOR_INPUT_DEV0: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV0; + bt848->iform &= ~BT848_IFORM_MUXSEL; + bt848->iform |= BT848_IFORM_M_MUX1; + bt848->e_control &= ~BT848_E_CONTROL_COMP; + bt848->o_control &= ~BT848_O_CONTROL_COMP; + set_audio( bktr, AUDIO_EXTERN ); + break; + + /* this is the tuner input */ + case METEOR_INPUT_DEV1: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV1; + bt848->iform &= ~BT848_IFORM_MUXSEL; + bt848->iform |= BT848_IFORM_M_MUX0; + bt848->e_control &= ~BT848_E_CONTROL_COMP; + bt848->o_control &= ~BT848_O_CONTROL_COMP; + set_audio( bktr, AUDIO_TUNER ); + break; + + /* this is the S-VHS input */ + case METEOR_INPUT_DEV2: + case METEOR_INPUT_DEV_SVIDEO: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV2; + bt848->iform &= ~BT848_IFORM_MUXSEL; + bt848->iform |= BT848_IFORM_M_MUX2; + bt848->e_control |= BT848_E_CONTROL_COMP; + bt848->o_control |= BT848_O_CONTROL_COMP; + set_audio( bktr, AUDIO_EXTERN ); + break; + + default: + return( EINVAL ); + } + break; + + case METEORGINPUT: /* get input device */ + *(u_long *)arg = bktr->flags & METEOR_DEV_MASK; + break; + + case METEORSACTPIXFMT: + if (( *(int *)arg < 0 ) || + ( *(int *)arg >= PIXFMT_TABLE_SIZE )) + return( EINVAL ); + + bktr->pixfmt = *(int *)arg; + bt848->color_ctl_swap = pixfmt_swap_flags( bktr->pixfmt ); + bktr->pixfmt_compat = FALSE; + break; + + case METEORGACTPIXFMT: + *(int *)arg = bktr->pixfmt; + break; + + case METEORGSUPPIXFMT : + pf_pub = (struct meteor_pixfmt *)arg; + pixfmt = pf_pub->index; + + if (( pixfmt < 0 ) || ( pixfmt >= PIXFMT_TABLE_SIZE )) + return( EINVAL ); + + memcpy( pf_pub, &pixfmt_table[ pixfmt ].public, + sizeof( *pf_pub ) ); + + /* Patch in our format index */ + pf_pub->index = pixfmt; + break; + +#if defined( STATUS_SUM ) + case BT848_GSTATUS: /* reap status */ + disable_intr(); + temp = status_sum; + status_sum = 0; + enable_intr(); + *(u_int*)arg = temp; + break; +#endif /* STATUS_SUM */ + + default: + return( ENOTTY ); + } + + return( 0 ); +} + + +/* + * + */ +int +bktr_mmap( dev_t dev, int offset, int nprot ) +{ + int unit; + bktr_ptr_t bktr; + + unit = UNIT(minor(dev)); + + if (unit >= NBKTR || MINOR(minor(dev)) > 0)/* could this happen here? */ + return( -1 ); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + bktr = bktr_cd.cd_devs[unit]; +#else + bktr = &(brooktree[ unit ]); +#endif + + if (nprot & PROT_EXEC) + return( -1 ); + + if (offset >= bktr->alloc_pages * PAGE_SIZE) + return( -1 ); + + return( i386_btop(vtophys(bktr->bigbuf) + offset) ); +} + + +/****************************************************************************** + * bt848 RISC programming routines: + */ + + +/* + * + */ +#ifdef BT848_DEBUG +static int +dump_bt848( bt848_ptr_t bt848 ) +{ + volatile u_char *bt848r = (u_char *)bt848; + int r[60]={ + 4, 8, 0xc, 0x8c, 0x10, 0x90, 0x14, 0x94, + 0x18, 0x98, 0x1c, 0x9c, 0x20, 0xa0, 0x24, 0xa4, + 0x28, 0x2c, 0xac, 0x30, 0x34, 0x38, 0x3c, 0x40, + 0xc0, 0x48, 0x4c, 0xcc, 0x50, 0xd0, 0xd4, 0x60, + 0x64, 0x68, 0x6c, 0xec, 0xd8, 0xdc, 0xe0, 0xe4, + 0, 0, 0, 0 + }; + int i; + + for (i = 0; i < 40; i+=4) { + printf(" Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n", + r[i], bt848r[r[i]], + r[i+1], bt848r[r[i+1]], + r[i+2], bt848r[r[i+2]], + r[i+3], bt848r[r[i+3]]); + } + + printf(" INT STAT %x \n", bt848->int_stat); + printf(" Reg INT_MASK %x \n", bt848->int_mask); + printf(" Reg GPIO_DMA_CTL %x \n", bt848->gpio_dma_ctl); + + return( 0 ); +} + +#endif + +/* + * build write instruction + */ +#define BKTR_FM1 0x6 /* packed data to follow */ +#define BKTR_FM3 0xe /* planar data to follow */ +#define BKTR_VRE 0x4 /* even field to follow */ +#define BKTR_VRO 0xC /* odd field to follow */ +#define BKTR_PXV 0x0 /* valid word (never used) */ +#define BKTR_EOL 0x1 /* last dword, 4 bytes */ +#define BKTR_SOL 0x2 /* first dword */ + +#define OP_WRITE (0x1 << 28) +#define OP_SKIP (0x2 << 28) +#define OP_WRITEC (0x5 << 28) +#define OP_JUMP (0x7 << 28) +#define OP_SYNC (0x8 << 28) +#define OP_WRITE123 (0x9 << 28) +#define OP_WRITES123 (0xb << 28) +#define OP_SOL (1 << 27) /* first instr for scanline */ +#define OP_EOL (1 << 26) + +bool_t notclipped (bktr_reg_t * bktr, int x, int width) { + int i; + bktr_clip_t * clip_node; + bktr->clip_start = -1; + bktr->last_y = 0; + bktr->y = 0; + bktr->y2 = width; + bktr->line_length = width; + bktr->yclip = -1; + bktr->yclip2 = -1; + bktr->current_col = 0; + + if (bktr->max_clip_node == 0 ) return TRUE; + clip_node = (bktr_clip_t *) &bktr->clip_list[0]; + + + for (i = 0; i < bktr->max_clip_node; i++ ) { + clip_node = (bktr_clip_t *) &bktr->clip_list[i]; + if (x >= clip_node->x_min && x <= clip_node->x_max ) { + bktr->clip_start = i; + return FALSE; + } + } + + return TRUE; +} + +bool_t getline(bktr_reg_t *bktr, int x ) { + int i, j; + bktr_clip_t * clip_node ; + + if (bktr->line_length == 0 || + bktr->current_col >= bktr->line_length) return FALSE; + + bktr->y = min(bktr->last_y, bktr->line_length); + bktr->y2 = bktr->line_length; + + bktr->yclip = bktr->yclip2 = -1; + for (i = bktr->clip_start; i < bktr->max_clip_node; i++ ) { + clip_node = (bktr_clip_t *) &bktr->clip_list[i]; + if (x >= clip_node->x_min && x <= clip_node->x_max) { + if (bktr->last_y <= clip_node->y_min) { + bktr->y = min(bktr->last_y, bktr->line_length); + bktr->y2 = min(clip_node->y_min, bktr->line_length); + bktr->yclip = min(clip_node->y_min, bktr->line_length); + bktr->yclip2 = min(clip_node->y_max, bktr->line_length); + bktr->last_y = bktr->yclip2; + bktr->clip_start = i; + + for (j = i+1; j < bktr->max_clip_node; j++ ) { + clip_node = (bktr_clip_t *) &bktr->clip_list[j]; + if (x >= clip_node->x_min && x <= clip_node->x_max) { + if (bktr->last_y >= clip_node->y_min) { + bktr->yclip2 = min(clip_node->y_max, bktr->line_length); + bktr->last_y = bktr->yclip2; + bktr->clip_start = j; + } + } else break ; + } + return TRUE; + } + } + } + + if (bktr->current_col <= bktr->line_length) { + bktr->current_col = bktr->line_length; + return TRUE; + } + return FALSE; +} + +static bool_t split(bktr_reg_t * bktr, volatile u_long **dma_prog, int width , + u_long operation, int pixel_width, + volatile u_char ** target_buffer, int cols ) { + + u_long flag, flag2; + struct meteor_pixfmt *pf = &pixfmt_table[ bktr->pixfmt ].public; + u_int skip, start_skip; + + /* For RGB24, we need to align the component in FIFO Byte Lane 0 */ + /* to the 1st byte in the mem dword containing our start addr. */ + /* BTW, we know this pixfmt's 1st byte is Blue; thus the start addr */ + /* must be Blue. */ + start_skip = 0; + if (( pf->type == METEOR_PIXTYPE_RGB ) && ( pf->Bpp == 3 )) + switch ( ((u_long) *target_buffer) % 4 ) { + case 2 : start_skip = 4 ; break; + case 1 : start_skip = 8 ; break; + } + + if ((width * pixel_width) < DMA_BT848_SPLIT ) { + if ( width == cols) { + flag = OP_SOL | OP_EOL; + } else if (bktr->current_col == 0 ) { + flag = OP_SOL; + } else if (bktr->current_col == cols) { + flag = OP_EOL; + } else flag = 0; + + skip = 0; + if (( flag & OP_SOL ) && ( start_skip > 0 )) { + *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip; + flag &= ~OP_SOL; + skip = start_skip; + } + + *(*dma_prog)++ = operation | flag | (width * pixel_width - skip); + if (operation != OP_SKIP ) + *(*dma_prog)++ = (u_long) *target_buffer; + + *target_buffer += width * pixel_width; + bktr->current_col += width; + + } else { + + if (bktr->current_col == 0 && width == cols) { + flag = OP_SOL ; + flag2 = OP_EOL; + } else if (bktr->current_col == 0 ) { + flag = OP_SOL; + flag2 = 0; + } else if (bktr->current_col >= cols) { + flag = 0; + flag2 = OP_EOL; + } else { + flag = 0; + flag2 = 0; + } + + skip = 0; + if (( flag & OP_SOL ) && ( start_skip > 0 )) { + *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip; + flag &= ~OP_SOL; + skip = start_skip; + } + + *(*dma_prog)++ = operation | flag | + (width * pixel_width / 2 - skip); + if (operation != OP_SKIP ) + *(*dma_prog)++ = (u_long ) *target_buffer ; + *target_buffer += (width * pixel_width / 2) ; + + if ( operation == OP_WRITE ) + operation = OP_WRITEC; + *(*dma_prog)++ = operation | flag2 | + (width * pixel_width / 2); + *target_buffer += (width * pixel_width / 2) ; + bktr->current_col += width; + + } + return TRUE; +} + + + + +static void +rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ) +{ + int i; + bt848_ptr_t bt848; + volatile u_long target_buffer, buffer, target,width; + volatile u_long pitch; + volatile u_long *dma_prog; + struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; + u_int Bpp = pf_int->public.Bpp; + + bt848 = bktr->base; + + bt848->color_fmt = pf_int->color_fmt; + bt848->vbi_pack_size = 0; + bt848->vbi_pack_del = 0; + bt848->adc = SYNC_LEVEL; + bt848->color_ctl_rgb_ded = 1; + +#ifndef ORIGINAL + bt848->color_ctl_gamma = 1; + bt848->oform = 0; + bt848->e_vscale_hi |= 0xc0; + bt848->o_vscale_hi |= 0xc0; +#else + bt848->e_vscale_hi |= 0xc0; + bt848->o_vscale_hi |= 0xc0; +#endif + if (cols > 385 ) { + bt848->e_vtc = 0; + bt848->o_vtc = 0; + } else { + bt848->e_vtc = 1; + bt848->o_vtc = 1; + } + bktr->capcontrol = 3 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + + if (bktr->video.addr) { + target_buffer = (u_long) bktr->video.addr; + pitch = bktr->video.width; + } + else { + target_buffer = (u_long) vtophys(bktr->bigbuf); + pitch = cols*Bpp; + } + + buffer = target_buffer; + + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM1; + + /* sync, mode indicator packed data */ + *dma_prog++ = 0; /* NULL WORD */ + width = cols; + for (i = 0; i < (rows/interlace); i++) { + target = target_buffer; + if ( notclipped(bktr, i, width)) { + split(bktr, (volatile u_long **) &dma_prog, + bktr->y2 - bktr->y, OP_WRITE, + Bpp, (volatile u_char **) &target, cols); + + } else { + while(getline(bktr, i)) { + if (bktr->y != bktr->y2 ) { + split(bktr, (volatile u_long **) &dma_prog, + bktr->y2 - bktr->y, OP_WRITE, + Bpp, (volatile u_char **) &target, cols); + } + if (bktr->yclip != bktr->yclip2 ) { + split(bktr,(volatile u_long **) &dma_prog, + bktr->yclip2 - bktr->yclip, + OP_SKIP, + Bpp, (volatile u_char **) &target, cols); + } + } + + } + + target_buffer += interlace * pitch; + + } + + switch (i_flag) { + case 1: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vro */ + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vro */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP; ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + target_buffer = buffer + pitch; + + dma_prog = (u_long *) bktr->odd_dma_prog; + + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM1; + *dma_prog++ = 0; /* NULL WORD */ + width = cols; + for (i = 0; i < (rows/interlace); i++) { + target = target_buffer; + if ( notclipped(bktr, i, width)) { + split(bktr, (volatile u_long **) &dma_prog, + bktr->y2 - bktr->y, OP_WRITE, + Bpp, (volatile u_char **) &target, cols); + } else { + while(getline(bktr, i)) { + if (bktr->y != bktr->y2 ) { + split(bktr, (volatile u_long **) &dma_prog, + bktr->y2 - bktr->y, OP_WRITE, + Bpp, (volatile u_char **) &target, + cols); + } + if (bktr->yclip != bktr->yclip2 ) { + split(bktr, (volatile u_long **) &dma_prog, + bktr->yclip2 - bktr->yclip, OP_SKIP, + Bpp, (volatile u_char **) &target, cols); + } + + } + + } + + target_buffer += interlace * pitch; + + } + } + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP ; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +static void +yuvpack_prog( bktr_ptr_t bktr, char i_flag, + int cols, int rows, int interlace ) +{ + int i; + volatile unsigned int inst; + volatile unsigned int inst3; + volatile u_long target_buffer, buffer; + bt848_ptr_t bt848; + volatile u_long *dma_prog; + struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; + int b; + + bt848 = bktr->base; + + bt848->color_fmt = pf_int->color_fmt; + + bt848->e_scloop |= BT848_E_SCLOOP_CAGC; /* enable chroma comb */ + bt848->o_scloop |= BT848_O_SCLOOP_CAGC; + + bt848->color_ctl_rgb_ded = 1; + bt848->color_ctl_gamma = 1; + bt848->adc = SYNC_LEVEL; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 1 << 2 | 3; + bktr->capcontrol = 3 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + + /* write , sol, eol */ + inst = OP_WRITE | OP_SOL | (cols); + /* write , sol, eol */ + inst3 = OP_WRITE | OP_EOL | (cols); + + if (bktr->video.addr) + target_buffer = (u_long) bktr->video.addr; + else + target_buffer = (u_long) vtophys(bktr->bigbuf); + + buffer = target_buffer; + + /* contruct sync : for video packet format */ + /* sync, mode indicator packed data */ + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM1; + *dma_prog++ = 0; /* NULL WORD */ + + b = cols; + + for (i = 0; i < (rows/interlace); i++) { + *dma_prog++ = inst; + *dma_prog++ = target_buffer; + *dma_prog++ = inst3; + *dma_prog++ = target_buffer + b; + target_buffer += interlace*(cols * 2); + } + + switch (i_flag) { + case 1: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vro */ + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vro */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + target_buffer = (u_long) buffer + cols*2; + + dma_prog = (u_long * ) bktr->odd_dma_prog; + + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_FM1; + *dma_prog++ = 0; /* NULL WORD */ + + for (i = 0; i < (rows/interlace) ; i++) { + *dma_prog++ = inst; + *dma_prog++ = target_buffer; + *dma_prog++ = inst3; + *dma_prog++ = target_buffer + b; + target_buffer += interlace * ( cols*2); + } + } + + /* sync vro IRQ bit */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP ; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +static void +yuv422_prog( bktr_ptr_t bktr, char i_flag, + int cols, int rows, int interlace ){ + + int i; + volatile unsigned int inst; + volatile u_long target_buffer, t1, buffer; + bt848_ptr_t bt848; + volatile u_long *dma_prog; + struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; + + bt848 = bktr->base; + + bt848->color_fmt = pf_int->color_fmt; + + dma_prog = (u_long *) bktr->dma_prog; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 3; + + bt848->adc = SYNC_LEVEL; + bt848->oform = 0x00; + + bt848->e_control |= BT848_E_CONTROL_LDEC; /* disable luma decimation */ + bt848->o_control |= BT848_O_CONTROL_LDEC; + + bt848->e_scloop |= BT848_O_SCLOOP_CAGC; /* chroma agc enable */ + bt848->o_scloop |= BT848_O_SCLOOP_CAGC; + + bt848->e_vscale_hi &= ~0x80; /* clear Ycomb */ + bt848->o_vscale_hi &= ~0x80; + bt848->e_vscale_hi |= 0x40; /* set chroma comb */ + bt848->o_vscale_hi |= 0x40; + + /* disable gamma correction removal */ + bt848->color_ctl_gamma = 1; + + /* Construct Write */ + inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols); + if (bktr->video.addr) + target_buffer = (u_long) bktr->video.addr; + else + target_buffer = (u_long) vtophys(bktr->bigbuf); + + buffer = target_buffer; + + t1 = buffer; + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/ + *dma_prog++ = 0; /* NULL WORD */ + + for (i = 0; i < (rows/interlace ) ; i++) { + *dma_prog++ = inst; + *dma_prog++ = cols/2 | cols/2 << 16; + *dma_prog++ = target_buffer; + *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; + *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace; + target_buffer += interlace*cols; + } + + switch (i_flag) { + case 1: + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP ; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + dma_prog = (u_long * ) bktr->odd_dma_prog; + + target_buffer = (u_long) buffer + cols; + t1 = buffer + cols/2; + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; + *dma_prog++ = 0; /* NULL WORD */ + + for (i = 0; i < (rows/interlace ) ; i++) { + *dma_prog++ = inst; + *dma_prog++ = cols/2 | cols/2 << 16; + *dma_prog++ = target_buffer; + *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; + *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace; + target_buffer += interlace*cols; + } + } + + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP ; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +static void +yuv12_prog( bktr_ptr_t bktr, char i_flag, + int cols, int rows, int interlace ){ + + int i; + volatile unsigned int inst; + volatile unsigned int inst1; + volatile u_long target_buffer, t1, buffer; + bt848_ptr_t bt848; + volatile u_long *dma_prog; + struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; + + bt848 = bktr->base; + + bt848->color_fmt = pf_int->color_fmt; + + dma_prog = (u_long *) bktr->dma_prog; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 3; + + bt848->adc = SYNC_LEVEL; + bt848->oform = 0x00; + + bt848->e_control |= BT848_E_CONTROL_LDEC; /* disable luma decimation */ + bt848->o_control |= BT848_O_CONTROL_LDEC; + + bt848->e_scloop |= BT848_O_SCLOOP_CAGC; /* chroma agc enable */ + bt848->o_scloop |= BT848_O_SCLOOP_CAGC; + + bt848->e_vscale_hi &= ~0x80; /* clear Ycomb */ + bt848->o_vscale_hi &= ~0x80; + bt848->e_vscale_hi |= 0x40; /* set chroma comb */ + bt848->o_vscale_hi |= 0x40; + + /* disable gamma correction removal */ + bt848->color_ctl_gamma = 1; + + /* Construct Write */ + inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols); + inst1 = OP_WRITES123 | OP_SOL | OP_EOL | (cols); + if (bktr->video.addr) + target_buffer = (u_long) bktr->video.addr; + else + target_buffer = (u_long) vtophys(bktr->bigbuf); + + buffer = target_buffer; + t1 = buffer; + + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/ + *dma_prog++ = 0; /* NULL WORD */ + + for (i = 0; i < (rows/interlace )/2 ; i++) { + *dma_prog++ = inst; + *dma_prog++ = cols/2 | (cols/2 << 16); + *dma_prog++ = target_buffer; + *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; + *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace; + target_buffer += interlace*cols; + *dma_prog++ = inst1; + *dma_prog++ = cols/2 | (cols/2 << 16); + *dma_prog++ = target_buffer; + target_buffer += interlace*cols; + + } + + switch (i_flag) { + case 1: + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vro*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + dma_prog = (u_long * ) bktr->odd_dma_prog; + + target_buffer = (u_long) buffer + cols; + t1 = buffer + cols/2; + *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; + *dma_prog++ = 0; /* NULL WORD */ + + for (i = 0; i < ((rows/interlace )/2 ) ; i++) { + *dma_prog++ = inst; + *dma_prog++ = cols/2 | (cols/2 << 16); + *dma_prog++ = target_buffer; + *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; + *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace; + target_buffer += interlace*cols; + *dma_prog++ = inst1; + *dma_prog++ = cols/2 | (cols/2 << 16); + *dma_prog++ = target_buffer; + target_buffer += interlace*cols; + + } + + + } + + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + *dma_prog++ = 0; /* NULL WORD */ +} + + + +/* + * + */ +static void +build_dma_prog( bktr_ptr_t bktr, char i_flag ) +{ + int rows, cols, interlace; + bt848_ptr_t bt848; + int tmp_int; + unsigned int temp; + struct format_params *fp; + struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; + + + fp = &format_params[bktr->format_params]; + + bt848 = bktr->base; + bt848->int_mask = ALL_INTS_DISABLED; + + /* disable FIFO & RISC, leave other bits alone */ + bt848->gpio_dma_ctl &= ~FIFO_RISC_ENABLED; + + /* set video parameters */ + temp = ((quad_t ) fp->htotal* (quad_t) fp->horizontal * 4096 + / fp->vertical / bktr->cols) - 4096; + bt848->e_hscale_lo = temp & 0xff; + bt848->o_hscale_lo = temp & 0xff; + bt848->e_hscale_hi = (temp >> 8) & 0xff; + bt848->o_hscale_hi = (temp >> 8) & 0xff; + + /* horizontal active */ + temp = bktr->cols; + bt848->e_hactive_lo = temp & 0xff; + bt848->o_hactive_lo = temp & 0xff; + bt848->e_crop &= ~0x3; + bt848->o_crop &= ~0x3; + bt848->e_crop |= (temp >> 8) & 0x3; + bt848->o_crop |= (temp >> 8) & 0x3; + + /* horizontal delay */ + temp = (fp->hdelay * bktr->cols) / fp->hactive; + temp = temp & 0x3fe; + bt848->e_delay_lo = temp & 0xff; + bt848->o_delay_lo = temp & 0xff; + bt848->e_crop &= ~0xc; + bt848->o_crop &= ~0xc; + bt848->e_crop |= (temp >> 6) & 0xc; + bt848->o_crop |= (temp >> 6) & 0xc; + + /* vertical scale */ + + if (bktr->flags & METEOR_ONLY_ODD_FIELDS || + bktr->flags & METEOR_ONLY_EVEN_FIELDS) + tmp_int = 65536 - + (((fp->vactive * 256 + (bktr->rows/2)) / bktr->rows) - 512); + else { + tmp_int = 65536 - + (((fp->vactive * 512 + (bktr->rows / 2)) / bktr->rows) - 512); + } + + tmp_int &= 0x1fff; + bt848->e_vscale_lo = tmp_int & 0xff; + bt848->o_vscale_lo = tmp_int & 0xff; + bt848->e_vscale_hi &= ~0x1f; + bt848->o_vscale_hi &= ~0x1f; + bt848->e_vscale_hi |= (tmp_int >> 8) & 0x1f; + bt848->o_vscale_hi |= (tmp_int >> 8) & 0x1f; + + + /* vertical active */ + bt848->e_crop &= ~0x30; + bt848->e_crop |= (fp->vactive >> 4) & 0x30; + bt848->e_vactive_lo = fp->vactive & 0xff; + bt848->o_crop &= ~0x30; + bt848->o_crop |= (fp->vactive >> 4) & 0x30; + bt848->o_vactive_lo = fp->vactive & 0xff; + + /* vertical delay */ + bt848->e_vdelay_lo = fp->vdelay; + bt848->o_vdelay_lo = fp->vdelay; + + /* end of video params */ + + /* capture control */ + switch (i_flag) { + case 1: + bktr->bktr_cap_ctl = + (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_EVEN); + bt848->e_vscale_hi &= ~0x20; + bt848->o_vscale_hi &= ~0x20; + interlace = 1; + break; + case 2: + bktr->bktr_cap_ctl = + (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_ODD); + bt848->e_vscale_hi &= ~0x20; + bt848->o_vscale_hi &= ~0x20; + interlace = 1; + break; + default: + bktr->bktr_cap_ctl = + (BT848_CAP_CTL_DITH_FRAME | + BT848_CAP_CTL_EVEN | BT848_CAP_CTL_ODD); + bt848->e_vscale_hi |= 0x20; + bt848->o_vscale_hi |= 0x20; + interlace = 2; + break; + } + + bt848->risc_strt_add = vtophys(bktr->dma_prog); + + rows = bktr->rows; + cols = bktr->cols; + + if ( pf_int->public.type == METEOR_PIXTYPE_RGB ) { + rgb_prog(bktr, i_flag, cols, rows, interlace); + return; + } + + if ( pf_int->public.type == METEOR_PIXTYPE_YUV ) { + yuv422_prog(bktr, i_flag, cols, rows, interlace); + bt848->color_ctl_swap = pixfmt_swap_flags( bktr->pixfmt ); + return; + } + + if ( pf_int->public.type == METEOR_PIXTYPE_YUV_PACKED ) { + yuvpack_prog(bktr, i_flag, cols, rows, interlace); + bt848->color_ctl_swap = pixfmt_swap_flags( bktr->pixfmt ); + return; + } + + if ( pf_int->public.type == METEOR_PIXTYPE_YUV_12 ) { + yuv12_prog(bktr, i_flag, cols, rows, interlace); + bt848->color_ctl_swap = pixfmt_swap_flags( bktr->pixfmt ); + return; + } + return; +} + + +/****************************************************************************** + * video & video capture specific routines: + */ + + +/* + * + */ +static void +start_capture( bktr_ptr_t bktr, unsigned type ) +{ + bt848_ptr_t bt848; + u_char i_flag; + struct format_params *fp; + + fp = &format_params[bktr->format_params]; + + bt848 = bktr->base; + + bt848->dstatus = 0; + bt848->int_stat = bt848->int_stat; + + bktr->flags |= type; + bktr->flags &= ~METEOR_WANT_MASK; + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + i_flag = 1; + break; + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + i_flag = 2; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + i_flag = 3; + break; + } + + /* TDEC is only valid for continuous captures */ + if ( type == METEOR_SINGLE ) { + u_short fps_save = bktr->fps; + + set_fps(bktr, fp->frame_rate); + bktr->fps = fps_save; + } + else + set_fps(bktr, bktr->fps); + + if (bktr->dma_prog_loaded == FALSE) { + build_dma_prog(bktr, i_flag); + bktr->dma_prog_loaded = TRUE; + } + + + bt848->risc_strt_add = vtophys(bktr->dma_prog); + +} + + +/* + * + */ +static void +set_fps( bktr_ptr_t bktr, u_short fps ) +{ + bt848_ptr_t bt848; + struct format_params *fp; + int i_flag; + + fp = &format_params[bktr->format_params]; + + bt848 = bktr->base; + + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + case METEOR_ONLY_EVEN_FIELDS: + bktr->flags |= METEOR_WANT_EVEN; + i_flag = 1; + break; + case METEOR_ONLY_ODD_FIELDS: + bktr->flags |= METEOR_WANT_ODD; + i_flag = 1; + break; + default: + bktr->flags |= METEOR_WANT_MASK; + i_flag = 2; + break; + } + + bt848->gpio_dma_ctl = FIFO_RISC_DISABLED; + bt848->int_stat = ALL_INTS_CLEARED; + + bktr->fps = fps; + bt848->tdec = 0; + + if (fps < fp->frame_rate) + bt848->tdec = i_flag*(fp->frame_rate - fps) & 0x3f; + else + bt848->tdec = 0; + return; + +} + + +/* + * There is also a problem with range checking on the 7116. + * It seems to only work for 22 bits, so the max size we can allocate + * is 22 bits long or 4194304 bytes assuming that we put the beginning + * of the buffer on a 2^24 bit boundary. The range registers will use + * the top 8 bits of the dma start registers along with the bottom 22 + * bits of the range register to determine if we go out of range. + * This makes getting memory a real kludge. + * + */ + +#define RANGE_BOUNDARY (1<<22) +#if defined(__NetBSD__) || defined(__OpenBSD__) +static vm_offset_t +get_bktr_mem(bktr, dmapp, size) + bktr_ptr_t bktr; + bus_dmamap_t *dmapp; + unsigned int size; +{ + bus_dma_tag_t dmat = bktr->dmat; + bus_dma_segment_t seg; + bus_size_t align; + int rseg; + caddr_t kva; + + /* + * Allocate a DMA area + */ + align = 1 << 24; + if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1, + &rseg, BUS_DMA_NOWAIT)) { + align = PAGE_SIZE; + if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1, + &rseg, BUS_DMA_NOWAIT)) { + printf("bktr%d: Unable to dmamem_alloc of %d bytes\n", + bktr->bktr_dev.dv_unit, size); + return 0; + } + } + if (bus_dmamem_map(dmat, &seg, rseg, size, + &kva, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC)) { + printf("bktr%d: Unable to dmamem_map of %d bytes\n", + bktr->bktr_dev.dv_unit, size); + bus_dmamem_free(dmat, &seg, rseg); + return 0; + } +#ifdef __OpenBSD__ + bktr->dm_mapsize = size; +#endif + /* + * Create and locd the DMA map for the DMA area + */ + if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) { + printf("bktr%d: Unable to dmamap_create of %d bytes\n", + bktr->bktr_dev.dv_unit, size); + bus_dmamem_unmap(dmat, kva, size); + bus_dmamem_free(dmat, &seg, rseg); + return 0; + } + if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) { + printf("bktr%d: Unable to dmamap_load of %d bytes\n", + bktr->bktr_dev.dv_unit, size); + bus_dmamem_unmap(dmat, kva, size); + bus_dmamem_free(dmat, &seg, rseg); + bus_dmamap_destroy(dmat, *dmapp); + return 0; + } + return (vm_offset_t)kva; +} + +static void +free_bktr_mem(bktr, dmap, kva) + bktr_ptr_t bktr; + bus_dmamap_t dmap; + vm_offset_t kva; +{ + bus_dma_tag_t dmat = bktr->dmat; + +#ifdef __NetBSD__ + bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize); +#else + bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize); +#endif + bus_dmamem_free(dmat, dmap->dm_segs, 1); + bus_dmamap_destroy(dmat, dmap); +} +#elif 0 +static vm_offset_t +get_bktr_mem( int unit, unsigned size ) +{ + vm_offset_t addr = 0; + + addr = (vm_offset_t)malloc(size, M_DEVBUF, M_WAITOK); + if (addr == 0) { + printf("bktr%d: Unable to allocate %d bytes of memory.\n", + unit, size); + } + return( addr ); +} +#else /* !__NetBSD__ */ +static vm_offset_t +get_bktr_mem( int unit, unsigned size ) +{ + vm_offset_t addr = 0; + + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, 1<<24); + if (addr == 0) + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, + PAGE_SIZE); + if (addr == 0) { + printf("bktr%d: Unable to allocate %d bytes of memory.\n", + unit, size); + } + + return( addr ); +} +#endif /* !__NetBSD__ */ + + + +/* + * Given a pixfmt index, compute the bt848 swap_flags necessary to + * achieve the specified swapping. + * Note that without bt swapping, 2Bpp and 3Bpp modes are written + * byte-swapped, and 4Bpp modes are byte and word swapped (see Table 6 + * and read R->L). + * Note also that for 3Bpp, we may additionally need to do some creative + * SKIPing to align the FIFO bytelines with the target buffer (see split()). + * This is abstracted here: e.g. no swaps = RGBA; byte & short swap = ABGR + * as one would expect. + */ + +static u_int pixfmt_swap_flags( int pixfmt ) +{ + struct meteor_pixfmt *pf = &pixfmt_table[ pixfmt ].public; + u_int swapf = 0; + + switch ( pf->Bpp ) { + case 2 : swapf = ( pf->swap_bytes ? 0 : BSWAP ); + break; + + case 3 : /* no swaps supported for 3bpp - makes no sense w/ bt848 */ + break; + + case 4 : if ( pf->swap_bytes ) + swapf = pf->swap_shorts ? 0 : WSWAP; + else + swapf = pf->swap_shorts ? BSWAP : (BSWAP | WSWAP); + break; + } + return swapf; +} + + + +/* + * Converts meteor-defined pixel formats (e.g. METEOR_GEO_RGB16) into + * our pixfmt_table indices. + */ + +static int oformat_meteor_to_bt( u_long format ) +{ + int i; + struct meteor_pixfmt *pf1, *pf2; + + /* Find format in compatibility table */ + for ( i = 0; i < METEOR_PIXFMT_TABLE_SIZE; i++ ) + if ( meteor_pixfmt_table[i].meteor_format == format ) + break; + + if ( i >= METEOR_PIXFMT_TABLE_SIZE ) + return -1; + pf1 = &meteor_pixfmt_table[i].public; + + /* Match it with an entry in master pixel format table */ + for ( i = 0; i < PIXFMT_TABLE_SIZE; i++ ) { + pf2 = &pixfmt_table[i].public; + + if (( pf1->type == pf2->type ) && + ( pf1->Bpp == pf2->Bpp ) && + !memcmp( pf1->masks, pf2->masks, sizeof( pf1->masks )) && + ( pf1->swap_bytes == pf2->swap_bytes ) && + ( pf1->swap_shorts == pf2->swap_shorts )) + break; + } + if ( i >= PIXFMT_TABLE_SIZE ) + return -1; + + return i; +} + +/****************************************************************************** + * i2c primitives: + */ + +/* */ +#define I2CBITTIME (0x5<<4) /* 5 * 0.48uS */ +#define I2C_READ 0x01 +#define I2C_COMMAND (I2CBITTIME | \ + BT848_DATA_CTL_I2CSCL | \ + BT848_DATA_CTL_I2CSDA) + +/* + * + */ +static int +i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ) +{ + u_long x; + u_long data; + bt848_ptr_t bt848; + + bt848 = bktr->base; + + /* clear status bits */ + bt848->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); + + /* build the command datum */ + data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND; + if ( byte2 != -1 ) { + data |= ((byte2 & 0xff) << 8); + data |= BT848_DATA_CTL_I2CW3B; + } + + /* write the address and data */ + bt848->i2c_data_ctl = data; + + /* wait for completion */ + for ( x = 0x7fffffff; x; --x ) { /* safety valve */ + if ( bt848->int_stat & BT848_INT_I2CDONE ) + break; + } + + /* check for ACK */ + if ( !x || !(bt848->int_stat & BT848_INT_RACK) ) + return( -1 ); + + /* return OK */ + return( 0 ); +} + + +/* + * + */ +static int +i2cRead( bktr_ptr_t bktr, int addr ) +{ + u_long x; + bt848_ptr_t bt848; + + bt848 = bktr->base; + + /* clear status bits */ + bt848->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); + + /* write the READ address */ + bt848->i2c_data_ctl = ((addr & 0xff) << 24) | I2C_COMMAND; + + /* wait for completion */ + for ( x = 0x7fffffff; x; --x ) { /* safety valve */ + if ( bt848->int_stat & BT848_INT_I2CDONE ) + break; + } + + /* check for ACK */ + if ( !x || !(bt848->int_stat & BT848_INT_RACK) ) + return( -1 ); + + /* it was a read */ + return( (bt848->i2c_data_ctl >> 8) & 0xff ); +} + + +#if defined( I2C_SOFTWARE_PROBE ) + +/* + * we are keeping this around for any parts that we need to probe + * but that CANNOT be probed via an i2c read. + * this is necessary because the hardware i2c mechanism + * cannot be programmed for 1 byte writes. + * currently there are no known i2c parts that we need to probe + * and that cannot be safely read. + */ +static int i2cProbe( bktr_ptr_t bktr, int addr ); +#define BITD 40 +#define EXTRA_START + +/* + * probe for an I2C device at addr. + */ +static int +i2cProbe( bktr_ptr_t bktr, int addr ) +{ + int x, status; + bt848_ptr_t bt848; + + bt848 = bktr->base; + + /* the START */ +#if defined( EXTRA_START ) + bt848->i2c_data_ctl = 1; DELAY( BITD ); /* release data */ + bt848->i2c_data_ctl = 3; DELAY( BITD ); /* release clock */ +#endif /* EXTRA_START */ + bt848->i2c_data_ctl = 2; DELAY( BITD ); /* lower data */ + bt848->i2c_data_ctl = 0; DELAY( BITD ); /* lower clock */ + + /* write addr */ + for ( x = 7; x >= 0; --x ) { + if ( addr & (1<<x) ) { + bt848->i2c_data_ctl = 1; + DELAY( BITD ); /* assert HI data */ + bt848->i2c_data_ctl = 3; + DELAY( BITD ); /* strobe clock */ + bt848->i2c_data_ctl = 1; + DELAY( BITD ); /* release clock */ + } + else { + bt848->i2c_data_ctl = 0; + DELAY( BITD ); /* assert LO data */ + bt848->i2c_data_ctl = 2; + DELAY( BITD ); /* strobe clock */ + bt848->i2c_data_ctl = 0; + DELAY( BITD ); /* release clock */ + } + } + + /* look for an ACK */ + bt848->i2c_data_ctl = 1; DELAY( BITD ); /* float data */ + bt848->i2c_data_ctl = 3; DELAY( BITD ); /* strobe clock */ + status = bt848->i2c_data_ctl & 1; /* read the ACK bit */ + bt848->i2c_data_ctl = 1; DELAY( BITD ); /* release clock */ + + /* the STOP */ + bt848->i2c_data_ctl = 0; DELAY( BITD ); /* lower clock & data */ + bt848->i2c_data_ctl = 2; DELAY( BITD ); /* release clock */ + bt848->i2c_data_ctl = 3; DELAY( BITD ); /* release data */ + + return( status ); +} +#undef EXTRA_START +#undef BITD + +#endif /* I2C_SOFTWARE_PROBE */ + + +/* + * + */ +static int +writeEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) +{ + return( -1 ); +} + + +/* + * + */ +static int +readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) +{ + int x; + int addr; + int max; + int byte; + + /* get the address of the EEProm */ + addr = (int)(bktr->card.eepromAddr & 0xff); + if ( addr == 0 ) + return( -1 ); + + max = (int)(bktr->card.eepromSize * EEPROMBLOCKSIZE); + if ( (offset + count) > max ) + return( -1 ); + + /* set the start address */ + if ( i2cWrite( bktr, addr, offset, -1 ) == -1 ) + return( -1 ); + + /* the read cycle */ + for ( x = 0; x < count; ++x ) { + if ( (byte = i2cRead( bktr, (addr | 1) )) == -1 ) + return( -1 ); + data[ x ] = byte; + } + + return( 0 ); +} + + +/****************************************************************************** + * card probe + */ + + +/* + * the recognized cards, used as indexes of several tables. + * + * if probeCard() fails to detect the proper card on boot you can + * override it by setting the following define to the card you are using: + * +#define OVERRIDE_CARD <card type> + * + * where <card type> is one of the following card defines. + */ +#define CARD_UNKNOWN 0 +#define CARD_MIRO 1 +#define CARD_HAUPPAUGE 2 +#define CARD_STB 3 +#define CARD_INTEL 4 + +/* + * the data for each type of card + * + * Note: + * these entried MUST be kept in the order defined by the CARD_XXX defines! + */ +static const struct CARDTYPE cards[] = { + + /* CARD_UNKNOWN */ + { "Unknown", /* the 'name' */ + NULL, /* the tuner */ + 0, /* dbx unknown */ + 0, + 0, /* EEProm unknown */ + 0, /* EEProm unknown */ + { 0, 0, 0, 0, 0 } }, + + /* CARD_MIRO */ + { "Miro TV", /* the 'name' */ + NULL, /* the tuner */ + 0, /* dbx unknown */ + 0, + PFC8582_WADDR, /* EEProm type */ + (u_char)(256 / EEPROMBLOCKSIZE), /* 256bytes */ + { 0x02, 0x01, 0x00, 0x0a, 1 } }, /* XXX ??? */ + + /* CARD_HAUPPAUGE */ + { "Hauppauge WinCast/TV", /* the 'name' */ + NULL, /* the tuner */ + 0, /* dbx is optional */ + 0, + PFC8582_WADDR, /* EEProm type */ + (u_char)(256 / EEPROMBLOCKSIZE), /* 256 bytes */ + { 0x00, 0x02, 0x01, 0x01, 1 } }, /* audio MUX values */ + + /* CARD_STB */ + { "STB TV/PCI", /* the 'name' */ + NULL, /* the tuner */ + 0, /* dbx is optional */ + 0, + X24C01_WADDR, /* EEProm type */ + (u_char)(128 / EEPROMBLOCKSIZE), /* 128 bytes */ + { 0x00, 0x01, 0x02, 0x02, 1 } }, /* audio MUX values */ + + /* CARD_INTEL */ + { "Intel Smart Video III/VideoLogic Captivator PCI", /* the 'name' */ + NULL, /* the tuner */ + 0, + 0, + 0, + 0, + { 0, 0, 0, 0, 0 } } +}; + + +/* + * the data for each type of tuner + * + * if probeCard() fails to detect the proper tuner on boot you can + * override it by setting the following define to the tuner present: + * +#define OVERRIDE_TUNER <tuner type> + * + * where <tuner type> is one of the following tuner defines. + */ + +/* indexes into tuners[] */ +#define NO_TUNER 0 +#define TEMIC_NTSC 1 +#define TEMIC_PAL 2 +#define TEMIC_SECAM 3 +#define PHILIPS_NTSC 4 +#define PHILIPS_PAL 5 +#define PHILIPS_SECAM 6 +#define TEMIC_PALI 7 +#define PHILIPS_PALI 8 +#define PHILIPS_FR1236_NTSC 9 +#define PHILIPS_FR1216_PAL 10 + +/* XXX FIXME: this list is incomplete */ + +/* input types */ +#define TTYPE_XXX 0 +#define TTYPE_NTSC 1 +#define TTYPE_NTSC_J 2 +#define TTYPE_PAL 3 +#define TTYPE_PAL_M 4 +#define TTYPE_PAL_N 5 +#define TTYPE_SECAM 6 + +/** +struct TUNER { + char* name; + u_char type; + u_char pllAddr; + u_char pllControl; + u_char bandLimits[ 2 ]; + u_char bandAddrs[ 3 ]; +}; + */ +static const struct TUNER tuners[] = { +/* XXX FIXME: fill in the band-switch crosspoints */ + /* NO_TUNER */ + { "<none>", /* the 'name' */ + TTYPE_XXX, /* input type */ + 0x00, /* PLL write address */ + { 0x00, /* control byte for PLL */ + 0x00, + 0x00, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0x00, 0x00, 0x00,0x00} }, /* the band-switch values */ + + /* TEMIC_NTSC */ + { "Temic NTSC", /* the 'name' */ + TTYPE_NTSC, /* input type */ + TEMIC_NTSC_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */ + + /* TEMIC_PAL */ + { "Temic PAL", /* the 'name' */ + TTYPE_PAL, /* input type */ + TEMIC_PALI_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */ + + /* TEMIC_SECAM */ + { "Temic SECAM", /* the 'name' */ + TTYPE_SECAM, /* input type */ + 0x00, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */ + + /* PHILIPS_NTSC */ + { "Philips NTSC", /* the 'name' */ + TTYPE_NTSC, /* input type */ + PHILIPS_NTSC_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */ + + /* PHILIPS_PAL */ + { "Philips PAL", /* the 'name' */ + TTYPE_PAL, /* input type */ + PHILIPS_PAL_WADDR, /* PLL write address */ + { TSA552x_FCONTROL, /* control byte for PLL */ + TSA552x_FCONTROL, + TSA552x_FCONTROL, + TSA552x_RADIO }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30, 0xa4 } }, /* the band-switch values */ + + /* PHILIPS_SECAM */ + { "Philips SECAM", /* the 'name' */ + TTYPE_SECAM, /* input type */ + 0x00, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + TSA552x_RADIO }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30,0xa4 } }, /* the band-switch values */ + + /* TEMIC_PAL I */ + { "Temic PAL I", /* the 'name' */ + TTYPE_PAL, /* input type */ + TEMIC_PALI_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */ + + /* PHILIPS_PAL */ + { "Philips PAL I", /* the 'name' */ + TTYPE_PAL, /* input type */ + TEMIC_PALI_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00 }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30,0x00 } }, /* the band-switch values */ + + /* PHILIPS_FR1236_NTSC */ + { "Philips FR1236 NTSC FM", /* the 'name' */ + TTYPE_NTSC, /* input type */ + PHILIPS_FR1236_NTSC_WADDR, /* PLL write address */ + { TSA552x_SCONTROL, /* control byte for PLL */ + TSA552x_SCONTROL, + TSA552x_SCONTROL, + 0x00}, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30,0x00 } }, /* the band-switch values */ + + /* PHILIPS_FR1216_PAL */ + { "Philips FR1216 PAL FM", /* the 'name' */ + TTYPE_PAL, /* input type */ + PHILIPS_FR1216_PAL_WADDR, /* PLL write address */ + { TSA552x_FCONTROL, /* control byte for PLL */ + TSA552x_FCONTROL, + TSA552x_FCONTROL, + TSA552x_RADIO }, + { 0x00, 0x00 }, /* band-switch crosspoints */ + { 0xa0, 0x90, 0x30, 0xa4 } }, /* the band-switch values */ +}; + + +/* + * get a signature of the card + * read all 128 possible i2c read addresses from 0x01 thru 0xff + * build a bit array with a 1 bit for each i2c device that responds + * + * XXX FIXME: use offset & count args + */ +#define ABSENT (-1) +static int +signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig ) +{ + int x; + + for ( x = 0; x < 16; ++x ) + sig[ x ] = 0; + + for ( x = 0; x < 128; ++x ) { + if ( i2cRead( bktr, (2 * x) + 1 ) != ABSENT ) { + sig[ x / 8 ] |= (1 << (x % 8) ); + } + } + + return( 0 ); +} + +/* + * any_i2c_devices. + * Some BT848/BT848A cards have no tuner and no additional i2c devices + * eg stereo decoder. These are used for video conferencing or capture from + * a video camera. (VideoLogic Captivator PCI, Intel SmartCapture card). + * + * Determine if there are any i2c devices present. There are none present if + * a) reading from all 128 devices returns ABSENT (-1) for each one + * (eg VideoLogic Captivator PCI with BT848) + * b) reading from all 128 devices returns 0 for each one + * (eg VideoLogic Captivator PCI rev. 2F with BT848A) + */ +static int check_for_i2c_devices( bktr_ptr_t bktr ){ + int x, temp_read; + int i2c_all_0 = 1; + int i2c_all_absent = 1; + for ( x = 0; x < 128; ++x ) { + temp_read = i2cRead( bktr, (2 * x) + 1 ); + if (temp_read != 0) i2c_all_0 = 0; + if (temp_read != ABSENT) i2c_all_absent = 0; + } + + if ((i2c_all_0) || (i2c_all_absent)) return 0; + else return 1; +} +#undef ABSENT + +/* + * determine the card brand/model + * OVERRIDE_CARD, OVERRIDE_TUNER, OVERRIDE_DBX and OVERRIDE_MSP + * can be used to select a specific device, regardless of the + * autodetection and i2c device checks. + */ +#define ABSENT (-1) + +static void +probeCard( bktr_ptr_t bktr, int verbose ) +{ + int card; + int status; + bt848_ptr_t bt848; + int any_i2c_devices; + + any_i2c_devices = check_for_i2c_devices( bktr ); + bt848 = bktr->base; + + bt848->gpio_out_en = 0; + if (bootverbose) + printf("bktr: GPIO is 0x%08x\n", bt848->gpio_data); + +#if defined( OVERRIDE_CARD ) + bktr->card = cards[ (card = OVERRIDE_CARD) ]; + goto checkTuner; +#endif + + /* Check for i2c devices */ + if (!any_i2c_devices) { + bktr->card = cards[ (card = CARD_INTEL) ]; + goto checkTuner; + } + + /* look for a tuner */ + if ( i2cRead( bktr, TSA552x_RADDR ) == ABSENT ) { + bktr->card = cards[ (card = CARD_INTEL) ]; + bktr->card.tuner = &tuners[ NO_TUNER ]; + goto checkDBX; + } + + /* look for a hauppauge card */ + if ( (status = i2cRead( bktr, PFC8582_RADDR )) != ABSENT ) { + bktr->card = cards[ (card = CARD_HAUPPAUGE) ]; + goto checkTuner; + } + + /* look for an STB card */ + if ( (status = i2cRead( bktr, X24C01_RADDR )) != ABSENT ) { + bktr->card = cards[ (card = CARD_STB) ]; + goto checkTuner; + } + + /* XXX FIXME: (how do I) look for a Miro card */ + bktr->card = cards[ (card = CARD_MIRO) ]; + +checkTuner: +#if defined( OVERRIDE_TUNER ) + bktr->card.tuner = &tuners[ OVERRIDE_TUNER ]; + goto checkDBX; +#endif + + /* Check for i2c devices */ + if (!any_i2c_devices) { + bktr->card.tuner = &tuners[ NO_TUNER ]; + goto checkDBX; + } + + /* differentiate type of tuner */ + switch (card) { + case CARD_MIRO: + switch (((bt848->gpio_data >> 10)-1)&7) { + case 0: bktr->card.tuner = &tuners[ TEMIC_PAL ]; break; + case 1: bktr->card.tuner = &tuners[ PHILIPS_PAL ]; break; + case 2: bktr->card.tuner = &tuners[ PHILIPS_NTSC ]; break; + case 3: bktr->card.tuner = &tuners[ PHILIPS_SECAM ]; break; + case 4: bktr->card.tuner = &tuners[ NO_TUNER ]; break; + case 5: bktr->card.tuner = &tuners[ PHILIPS_PALI ]; break; + case 6: bktr->card.tuner = &tuners[ TEMIC_NTSC ]; break; + case 7: bktr->card.tuner = &tuners[ TEMIC_PALI ]; break; + } + break; + default: + if ( i2cRead( bktr, TEMIC_NTSC_RADDR ) != ABSENT ) { + bktr->card.tuner = &tuners[ TEMIC_NTSC ]; + goto checkDBX; + } + + if ( i2cRead( bktr, PHILIPS_NTSC_RADDR ) != ABSENT ) { + bktr->card.tuner = &tuners[ PHILIPS_NTSC ]; + goto checkDBX; + } + + if ( card == CARD_HAUPPAUGE ) { + if ( i2cRead( bktr, TEMIC_PALI_RADDR ) != ABSENT ) { + bktr->card.tuner = &tuners[ TEMIC_PAL ]; + goto checkDBX; + } + } + /* no tuner found */ + bktr->card.tuner = &tuners[ NO_TUNER ]; + } + +checkDBX: +#if defined( OVERRIDE_DBX ) + bktr->card.dbx = OVERRIDE_DBX; + goto checkMSP; +#endif + /* Check for i2c devices */ + if (!any_i2c_devices) { + goto checkMSP; + } + + /* probe for BTSC (dbx) chip */ + if ( i2cRead( bktr, TDA9850_RADDR ) != ABSENT ) + bktr->card.dbx = 1; + +checkMSP: +#if defined( OVERRIDE_MSP ) + bktr->card.msp3400c = OVERRIDE_MSP; + goto checkEnd; +#endif + /* Check for i2c devices */ + if (!any_i2c_devices) { + goto checkEnd; + } + + if ( i2cRead( bktr, MSP3400C_RADDR ) != ABSENT ) + bktr->card.msp3400c = 1; + +checkEnd: + + if ( verbose ) { + printf( "%s", bktr->card.name ); + if ( bktr->card.tuner ) + printf( ", %s tuner", bktr->card.tuner->name ); + if ( bktr->card.dbx ) + printf( ", dbx stereo" ); + if ( bktr->card.msp3400c ) + printf( ", msp3400c stereo" ); + printf( ".\n" ); + } +} +#undef ABSENT + + +/****************************************************************************** + * tuner specific routines: + */ + + +/* scaling factor for frequencies expressed as ints */ +#define FREQFACTOR 16 + +/* + * Format: + * entry 0: MAX legal channel + * entry 1: IF frequency + * expressed as fi{mHz} * 16, + * eg 45.75mHz == 45.75 * 16 = 732 + * entry 2: [place holder/future] + * entry 3: base of channel record 0 + * entry 3 + (x*3): base of channel record 'x' + * entry LAST: NULL channel entry marking end of records + * + * Record: + * int 0: base channel + * int 1: frequency of base channel, + * expressed as fb{mHz} * 16, + * int 2: offset frequency between channels, + * expressed as fo{mHz} * 16, + */ + +/* + * North American Broadcast Channels: + * + * 2: 55.25 mHz - 4: 67.25 mHz + * 5: 77.25 mHz - 6: 83.25 mHz + * 7: 175.25 mHz - 13: 211.25 mHz + * 14: 471.25 mHz - 83: 885.25 mHz + * + * IF freq: 45.75 mHz + */ +#define OFFSET 6.00 +static int nabcst[] = { + 83, (int)( 45.75 * FREQFACTOR), 0, + 14, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 0 +}; +#undef OFFSET + +/* + * North American Cable Channels, IRC: + * + * 2: 55.25 mHz - 4: 67.25 mHz + * 5: 77.25 mHz - 6: 83.25 mHz + * 7: 175.25 mHz - 13: 211.25 mHz + * 14: 121.25 mHz - 22: 169.25 mHz + * 23: 217.25 mHz - 94: 643.25 mHz + * 95: 91.25 mHz - 99: 115.25 mHz + * + * IF freq: 45.75 mHz + */ +#define OFFSET 6.00 +static int irccable[] = { + 99, (int)( 45.75 * FREQFACTOR), 0, + 95, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 23, (int)(217.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 14, (int)(121.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 0 +}; +#undef OFFSET + +/* + * North American Cable Channels, HRC: + * + * 2: 54 mHz - 4: 66 mHz + * 5: 78 mHz - 6: 84 mHz + * 7: 174 mHz - 13: 210 mHz + * 14: 120 mHz - 22: 168 mHz + * 23: 216 mHz - 94: 642 mHz + * 95: 90 mHz - 99: 114 mHz + * + * IF freq: 45.75 mHz + */ +#define OFFSET 6.00 +static int hrccable[] = { + 99, (int)( 45.75 * FREQFACTOR), 0, + 95, (int)( 90.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 23, (int)(216.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 14, (int)(120.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 7, (int)(174.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 5, (int)( 78.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 2, (int)( 54.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 0 +}; +#undef OFFSET + +/* + * Western European broadcast channels: + * + * (there are others that appear to vary between countries - rmt) + * + * here's the table Philips provides: + * caution, some of the offsets don't compute... + * + * 1 4525 700 N21 + * + * 2 4825 700 E2 + * 3 5525 700 E3 + * 4 6225 700 E4 + * + * 5 17525 700 E5 + * 6 18225 700 E6 + * 7 18925 700 E7 + * 8 19625 700 E8 + * 9 20325 700 E9 + * 10 21025 700 E10 + * 11 21725 700 E11 + * 12 22425 700 E12 + * + * 13 5375 700 ITA + * 14 6225 700 ITB + * + * 15 8225 700 ITC + * + * 16 17525 700 ITD + * 17 18325 700 ITE + * + * 18 19225 700 ITF + * 19 20125 700 ITG + * 20 21025 700 ITH + * + * 21 47125 800 E21 + * 22 47925 800 E22 + * 23 48725 800 E23 + * 24 49525 800 E24 + * 25 50325 800 E25 + * 26 51125 800 E26 + * 27 51925 800 E27 + * 28 52725 800 E28 + * 29 53525 800 E29 + * 30 54325 800 E30 + * 31 55125 800 E31 + * 32 55925 800 E32 + * 33 56725 800 E33 + * 34 57525 800 E34 + * 35 58325 800 E35 + * 36 59125 800 E36 + * 37 59925 800 E37 + * 38 60725 800 E38 + * 39 61525 800 E39 + * 40 62325 800 E40 + * 41 63125 800 E41 + * 42 63925 800 E42 + * 43 64725 800 E43 + * 44 65525 800 E44 + * 45 66325 800 E45 + * 46 67125 800 E46 + * 47 67925 800 E47 + * 48 68725 800 E48 + * 49 69525 800 E49 + * 50 70325 800 E50 + * 51 71125 800 E51 + * 52 71925 800 E52 + * 53 72725 800 E53 + * 54 73525 800 E54 + * 55 74325 800 E55 + * 56 75125 800 E56 + * 57 75925 800 E57 + * 58 76725 800 E58 + * 59 77525 800 E59 + * 60 78325 800 E60 + * 61 79125 800 E61 + * 62 79925 800 E62 + * 63 80725 800 E63 + * 64 81525 800 E64 + * 65 82325 800 E65 + * 66 83125 800 E66 + * 67 83925 800 E67 + * 68 84725 800 E68 + * 69 85525 800 E69 + * + * 70 4575 800 IA + * 71 5375 800 IB + * 72 6175 800 IC + * + * 74 6925 700 S01 + * 75 7625 700 S02 + * 76 8325 700 S03 + * + * 80 10525 700 S1 + * 81 11225 700 S2 + * 82 11925 700 S3 + * 83 12625 700 S4 + * 84 13325 700 S5 + * 85 14025 700 S6 + * 86 14725 700 S7 + * 87 15425 700 S8 + * 88 16125 700 S9 + * 89 16825 700 S10 + * 90 23125 700 S11 + * 91 23825 700 S12 + * 92 24525 700 S13 + * 93 25225 700 S14 + * 94 25925 700 S15 + * 95 26625 700 S16 + * 96 27325 700 S17 + * 97 28025 700 S18 + * 98 28725 700 S19 + * 99 29425 700 S20 + * + * + * Channels S21 - S41 are taken from + * http://gemma.apple.com:80/dev/technotes/tn/tn1012.html + * + * 100 30325 800 S21 + * 101 31125 800 S22 + * 102 31925 800 S23 + * 103 32725 800 S24 + * 104 33525 800 S25 + * 105 34325 800 S26 + * 106 35125 800 S27 + * 107 35925 800 S28 + * 108 36725 800 S29 + * 109 37525 800 S30 + * 110 38325 800 S31 + * 111 39125 800 S32 + * 112 39925 800 S33 + * 113 40725 800 S34 + * 114 41525 800 S35 + * 115 42325 800 S36 + * 116 43125 800 S37 + * 117 43925 800 S38 + * 118 44725 800 S39 + * 119 45525 800 S40 + * 120 46325 800 S41 + * + * 121 3890 000 IFFREQ + * + */ +static int weurope[] = { + 121, (int)( 38.90 * FREQFACTOR), 0, + 100, (int)(303.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR), + 90, (int)(231.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR), + 80, (int)(105.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR), + 74, (int)( 69.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR), + 21, (int)(471.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR), + 17, (int)(183.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR), + 16, (int)(175.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR), + 15, (int)(82.25 * FREQFACTOR), (int)(8.50 * FREQFACTOR), + 13, (int)(53.75 * FREQFACTOR), (int)(8.50 * FREQFACTOR), + 5, (int)(175.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR), + 2, (int)(48.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR), + 0 +}; + +/* + * Japanese Broadcast Channels: + * + * 1: 91.25MHz - 3: 103.25MHz + * 4: 171.25MHz - 7: 189.25MHz + * 8: 193.25MHz - 12: 217.25MHz (VHF) + * 13: 471.25MHz - 62: 765.25MHz (UHF) + * + * IF freq: 45.75 mHz + * OR + * IF freq: 58.75 mHz + */ +#define OFFSET 6.00 +#define IF_FREQ 45.75 +static int jpnbcst[] = { + 62, (int)(IF_FREQ * FREQFACTOR), 0, + 13, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 0 +}; +#undef IF_FREQ +#undef OFFSET + +/* + * Japanese Cable Channels: + * + * 1: 91.25MHz - 3: 103.25MHz + * 4: 171.25MHz - 7: 189.25MHz + * 8: 193.25MHz - 12: 217.25MHz + * 13: 109.25MHz - 21: 157.25MHz + * 22: 165.25MHz + * 23: 223.25MHz - 63: 463.25MHz + * + * IF freq: 45.75 mHz + */ +#define OFFSET 6.00 +#define IF_FREQ 45.75 +static int jpncable[] = { + 63, (int)(IF_FREQ * FREQFACTOR), 0, + 23, (int)(223.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 22, (int)(165.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 13, (int)(109.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), + 0 +}; +#undef IF_FREQ +#undef OFFSET + +static int* freqTable[] = { + NULL, + nabcst, + irccable, + hrccable, + weurope, + jpnbcst, + jpncable + +}; + + +#define TBL_CHNL freqTable[ bktr->tuner.chnlset ][ x ] +#define TBL_BASE_FREQ freqTable[ bktr->tuner.chnlset ][ x + 1 ] +#define TBL_OFFSET freqTable[ bktr->tuner.chnlset ][ x + 2 ] +static int +frequency_lookup( bktr_ptr_t bktr, int channel ) +{ + int x; + + /* check for "> MAX channel" */ + x = 0; + if ( channel > TBL_CHNL ) + return( -1 ); + + /* search the table for data */ + for ( x = 3; TBL_CHNL; x += 3 ) { + if ( channel >= TBL_CHNL ) { + return( TBL_BASE_FREQ + + ((channel - TBL_CHNL) * TBL_OFFSET) ); + } + } + + /* not found, must be below the MIN channel */ + return( -1 ); +} +#undef TBL_OFFSET +#undef TBL_BASE_FREQ +#undef TBL_CHNL + + +#define TBL_IF freqTable[ bktr->tuner.chnlset ][ 1 ] +/* + * set the frequency of the tuner + */ +static int +tv_freq( bktr_ptr_t bktr, int frequency ) +{ + const struct TUNER* tuner; + u_char addr; + u_char control; + u_char band; + int N; + + tuner = bktr->card.tuner; + if ( tuner == NULL ) + return( -1 ); + + /* + * select the band based on frequency + * XXX FIXME: get the cross-over points from the tuner struct + */ + if ( frequency < (160 * FREQFACTOR) ) + N = 0; + else if ( frequency < (454 * FREQFACTOR) ) + N = 1; + else + N = 2; + + if(frequency > RADIO_OFFSET) { + N=3; + frequency -= RADIO_OFFSET; + } + + /* set the address of the PLL */ + addr = tuner->pllAddr; + control = tuner->pllControl[ N ]; + band = tuner->bandAddrs[ N ]; + if(!(band && control)) /* Don't try to set un- */ + return(-1); /* supported modes. */ + + if(N==3) + band |= bktr->tuner.radio_mode; + + /* + * N = 16 * { fRF(pc) + fIF(pc) } + * where: + * pc is picture carrier, fRF & fIF are in mHz + * + * frequency was passed in as mHz * 16 + */ +#if defined( TEST_TUNER_AFC ) + if ( bktr->tuner.afc ) + frequency -= 4; +#endif + N = frequency + TBL_IF; + + if ( frequency > bktr->tuner.frequency ) { + i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff ); + i2cWrite( bktr, addr, control, band ); + } + else { + i2cWrite( bktr, addr, control, band ); + i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff ); + } + +#if defined( TUNER_AFC ) + if ( bktr->tuner.afc == TRUE ) { + if ( (N = do_afc( bktr, addr, N )) < 0 ) { + /* AFC failed, restore requested frequency */ + N = frequency + TBL_IF; + i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff ); + } + else + frequency = N - TBL_IF; + } +#endif /* TUNER_AFC */ + + /* update frequency */ + bktr->tuner.frequency = frequency; + + return( 0 ); +} + +#if defined( TUNER_AFC ) +/* + * + */ +static int +do_afc( bktr_ptr_t bktr, int addr, int frequency ) +{ + int step; + int status; + int origFrequency; + + origFrequency = frequency; + + /* wait for first setting to take effect */ + tsleep( (caddr_t)bktr, PZERO, "tuning", hz/8 ); + + if ( (status = i2cRead( bktr, addr + 1 )) < 0 ) + return( -1 ); + +#if defined( TEST_TUNER_AFC ) + printf( "\nOriginal freq: %d, status: 0x%02x\n", frequency, status ); +#endif + for ( step = 0; step < AFC_MAX_STEP; ++step ) { + if ( (status = i2cRead( bktr, addr + 1 )) < 0 ) + goto fubar; + if ( !(status & 0x40) ) { +#if defined( TEST_TUNER_AFC ) + printf( "no lock!\n" ); +#endif + goto fubar; + } + + switch( status & AFC_BITS ) { + case AFC_FREQ_CENTERED: +#if defined( TEST_TUNER_AFC ) + printf( "Centered, freq: %d, status: 0x%02x\n", frequency, status ); +#endif + return( frequency ); + + case AFC_FREQ_MINUS_125: + case AFC_FREQ_MINUS_62: +#if defined( TEST_TUNER_AFC ) + printf( "Low, freq: %d, status: 0x%02x\n", frequency, status ); +#endif + --frequency; + break; + + case AFC_FREQ_PLUS_62: + case AFC_FREQ_PLUS_125: +#if defined( TEST_TUNER_AFC ) + printf( "Hi, freq: %d, status: 0x%02x\n", frequency, status ); +#endif + ++frequency; + break; + } + + i2cWrite( bktr, addr, + (frequency>>8) & 0x7f, frequency & 0xff ); + DELAY( AFC_DELAY ); + } + + fubar: + i2cWrite( bktr, addr, + (origFrequency>>8) & 0x7f, origFrequency & 0xff ); + + return( -1 ); +} +#endif /* TUNER_AFC */ +#undef TBL_IF + + +/* + * set the channel of the tuner + */ +static int +tv_channel( bktr_ptr_t bktr, int channel ) +{ + int frequency; + + /* calculate the frequency according to tuner type */ + if ( (frequency = frequency_lookup( bktr, channel )) < 0 ) + return( -1 ); + + /* set the new frequency */ + if ( tv_freq( bktr, frequency ) < 0 ) + return( -1 ); + + /* OK to update records */ + return( (bktr->tuner.channel = channel) ); +} + + +/****************************************************************************** + * audio specific routines: + */ + + +/* + * + */ +#define AUDIOMUX_DISCOVER_NOT +static int +set_audio( bktr_ptr_t bktr, int cmd ) +{ + bt848_ptr_t bt848; + u_long temp; + volatile u_char idx; + +#if defined( AUDIOMUX_DISCOVER ) + if ( cmd >= 200 ) + cmd -= 200; + else +#endif /* AUDIOMUX_DISCOVER */ + + /* check for existance of audio MUXes */ + if ( !bktr->card.audiomuxs[ 4 ] ) + return( -1 ); + + switch (cmd) { + case AUDIO_TUNER: +#ifdef BKTR_REVERSEMUTE + bktr->audio_mux_select = 3; +#else + bktr->audio_mux_select = 0; +#endif + break; + case AUDIO_EXTERN: + bktr->audio_mux_select = 1; + break; + case AUDIO_INTERN: + bktr->audio_mux_select = 2; + break; + case AUDIO_MUTE: + bktr->audio_mute_state = TRUE; /* set mute */ + break; + case AUDIO_UNMUTE: + bktr->audio_mute_state = FALSE; /* clear mute */ + break; + default: + printf("bktr: audio cmd error %02x\n", cmd); + return( -1 ); + } + + bt848 = bktr->base; + + /* + * Leave the upper bits of the GPIO port alone in case they control + * something like the dbx or teletext chips. This doesn't guarantee + * success, but follows the rule of least astonishment. + */ + + /* XXX FIXME: this was an 8 bit reference before new struct ??? */ + bt848->gpio_reg_inp = (~GPIO_AUDIOMUX_BITS & 0xff); + + if ( bktr->audio_mute_state == TRUE ) +#ifdef BKTR_REVERSEMUTE + idx = 0; +#else + idx = 3; +#endif + else + idx = bktr->audio_mux_select; + + temp = bt848->gpio_data & ~GPIO_AUDIOMUX_BITS; + bt848->gpio_data = +#if defined( AUDIOMUX_DISCOVER ) + bt848->gpio_data = temp | (cmd & 0xff); + printf("cmd: %d\n", cmd ); +#else + temp | bktr->card.audiomuxs[ idx ]; +#endif /* AUDIOMUX_DISCOVER */ + + return( 0 ); +} + + +/* + * + */ +static void +temp_mute( bktr_ptr_t bktr, int flag ) +{ + static int muteState = FALSE; + + if ( flag == TRUE ) { + muteState = bktr->audio_mute_state; + set_audio( bktr, AUDIO_MUTE ); /* prevent 'click' */ + } + else { + tsleep( (caddr_t)bktr, PZERO, "tuning", hz/8 ); + if ( muteState == FALSE ) + set_audio( bktr, AUDIO_UNMUTE ); + } +} + + +/* + * setup the dbx chip + * XXX FIXME: alot of work to be done here, this merely unmutes it. + */ +static int +set_BTSC( bktr_ptr_t bktr, int control ) +{ + return( i2cWrite( bktr, TDA9850_WADDR, CON3ADDR, control ) ); +} + + +/****************************************************************************** + * magic: + */ + + +#ifdef __FreeBSD__ +static bktr_devsw_installed = 0; + +static void +bktr_drvinit( void *unused ) +{ + dev_t dev; + + if ( ! bktr_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev,&bktr_cdevsw, NULL); + bktr_devsw_installed = 1; + } +} + +SYSINIT(bktrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bktr_drvinit,NULL) + +#endif /* __FreeBSD__ */ + +#if 0 +#if defined(__NetBSD__)||defined(__OpenBSD__) +#ifdef UVM +vm_offset_t +vm_page_alloc_contig(size, low, high, alignment) + vm_offset_t size; + vm_offset_t low; + vm_offset_t high; + vm_offset_t alignment; +{ + struct pglist mlist, *m; + vm_offset_t addr, tmp_addr; + + TAILQ_INIT(&mlist); + if (uvm_pglistalloc(size, low, high, alignment, 0, &mlist, 1, FALSE)) + return 0; + if (uvm_km_kmemalloc(kernel_map, uvmexp.kmem_object, + size, UVM_MKF_VALLOC) == 0) { + uvm_pglistfree(&mlist); + return 0; + } + return addr; +} +#else /* !UVM */ + +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +vm_offset_t +vm_page_alloc_contig(size, low, high, alignment) + vm_offset_t size; + vm_offset_t low; + vm_offset_t high; + vm_offset_t alignment; +{ + struct pglist mlist; + struct vm_page *m; + vm_offset_t addr, tmp_addr; + + TAILQ_INIT(&mlist); + if (vm_page_alloc_memory(size, low, high, alignment, 0, + &mlist, 1, FALSE)) + return 0; + addr = tmp_addr = kmem_alloc_pageable(kernel_map, size); + for (m = TAILQ_FIRST(&mlist); m != NULL; m = TAILQ_NEXT(m, pageq)) { + vm_page_insert(m, kernel_object, + tmp_addr - VM_MIN_KERNEL_ADDRESS); + vm_page_wire(m); + pmap_enter(pmap_kernel(), tmp_addr, VM_PAGE_TO_PHYS(m), + VM_PROT_READ|VM_PROT_WRITE, TRUE); + tmp_addr += PAGE_SIZE; + } + return addr; +} +#endif /* !UVM */ +#endif /* __NetBSD__ */ +#endif + +#endif /* !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) || (NBKTR > 0 && NPCI > 0) */ + +/* Local Variables: */ +/* mode: C */ +/* c-indent-level: 8 */ +/* c-brace-offset: -8 */ +/* c-argdecl-indent: 8 */ +/* c-label-offset: -8 */ +/* c-continued-statement-offset: 8 */ +/* c-tab-always-indent: nil */ +/* tab-width: 8 */ +/* End: */ diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 2bb11489014..320ae5709d2 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.17 1998/07/07 22:44:05 csapuntz Exp $ +# $OpenBSD: files.pci,v 1.18 1998/07/23 08:38:28 deraadt Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config.new file and device description for machine-independent PCI code. @@ -84,3 +84,8 @@ file dev/pci/if_fxp.c fxp device sv: audio, auconv, mulaw attach sv at pci file dev/pci/sv.c sv + +# Brooktree Bt848 video capture +device bktr: pcibus +attach bktr at pci +file dev/pci/brooktree848.c bktr needs-count |