mgavideo.c
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:38k
- /*
- * Video Capture Driver ( Video for Linux 1/2 )
- * for the Matrox Marvel G200 and Rainbow Runner-G series
- *
- * This module is an interface to the G100 and G200 video extension
- * registers.
- *
- * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
- *****************************************************************************
- * Version History:
- * V1.0 Ryan Drake Initial version by Ryan Drake
- * V1.1 Gerard v.d. Horst Activated the backend scaler
- */
- #ifndef __KERNEL__
- #define __KERNEL__
- #endif
- #ifndef MODULE
- #define MODULE
- #endif
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/malloc.h>
- #include <linux/poll.h>
- #include <asm/io.h>
- #include <linux/pci.h>
- #include <linux/interrupt.h>
- #include "mgavideo.h"
- #include "tuner.h"
- #include "msp3400.h"
- #include "ks0127.h"
- #include "zr36060.h"
- #define dprintk if (debug) printk
- static int debug = 0; /* insmod parameter */
- static int memsize = 8192 * 1024;
- #if LINUX_VERSION_CODE >= 0x020100
- MODULE_PARM(debug,"i");
- MODULE_PARM(memsize,"i");
- #endif
- /* i2c registers */
- #define PALWTADD 0x3c00
- #define X_DATAREG 0x3c0a
- #define XMISCCTRL 0x1e
- #define XGENIOCTRL 0x2a
- #define XGENIODATA 0x2b
- #define XKEYOPMODE 0x51
- #define XCOLMSK0RED 0x52
- #define XCOLMSK0GREEN 0x53
- #define XCOLMSK0BLUE 0x54
- #define XCOLKEY0RED 0x55
- #define XCOLKEY0GREEN 0x56
- #define XCOLKEY0BLUE 0x57
- #define SDA 0x10
- #define SCL 0x20
- #define I2C_DELAY 10
- /****************************************************************************
- * raw register access : these routines directly interact with the mga's
- * control aperature. must not be called until after
- * the board's pci memory has been mapped.
- ****************************************************************************/
- static u32 _mgaread( struct mga_dev* mga, u32 reg )
- {
- return readl( mga->ctrl + reg );
- }
- static u8 _mgareadb(struct mga_dev* mga, u32 reg )
- {
- return readb(mga->ctrl + reg );
- }
- #ifdef NEVER
- static u16 _mgareadw(struct mga_dev* mga, u32 reg )
- {
- return readw(mga->ctrl + reg );
- }
- #endif
- static void _mgawrite( struct mga_dev* mga, u32 reg, u32 data )
- {
- writel( data, mga->ctrl + reg );
- }
- static void _mgawriteb( struct mga_dev* mga, u32 reg, u32 data )
- {
- writeb( data, mga->ctrl + reg );
- }
- static void _mgawritew( struct mga_dev* mga, u32 reg, u32 data )
- {
- writeb( data, mga->ctrl + reg );
- }
- /****************************************************************************
- * Codec Interface *
- ****************************************************************************/
- /* Notes:
- This interface is made to work with the Zoran DVD Codec. More specifically it
- implements 8 bit VMI protocol A, with a big endian target chip.
- Tell me if it works with the ZR36060, or what needs to be configurable (byte order, bus size ?)
- It also uses a fixed 128Kb buffer size.
- There is room for improvements:
- 1. if the previous command is a write we can concatenate the datas instead of wasting 8 bytes
- for each write command
- 2. the command buffer is only 512 bytes wide. We can have on in kernel memory and only
- write the content on the MGA framebuffer at execute time. This could speed up memory access,
- and provide a solution that doesn't change the content of the framebuffer, as we don't have
- a reserved buffer yet (X fb memory management stuff to the rescue...)
- */
- /*
- * CODECCTL fields and commands
- */
- #define codecen 0x0001 /* CODEC enable, invert to disable */
- #define codecmode 0x0002 /* CODEC l33 mode, invert for VMI mode */
- #define cmdexectrig 0x0004 /* command execution trigger, invert to prevent execution */
- #define codecdatain 0x0008 /* compression, invert for decompression */
- #define vmimode 0x0010 /* VMI mode B, invert for mode A */
- #define stopcodec 0x0020 /* stop after current field, invert to not stop */
- #define codectransen 0x0040 /* enable transfer, invert to disable */
- #define CODEC_CMD(count, pause, stop, addr, read) ( (count) | ((pause) << 8) | ((stop) << 9) | ((addr) << 10) | ((read) << 15) )
- #define CODEC_WRITE(addr, byte) ( ((addr) << 8) | (byte) )
- #define RESET_CODEC_CMD_PTR mga->codeccmd = mga->codecaddr + 0x0020000
- #define RESET_CODEC_DATA_PTR mga->codecdata = mga->codecaddr + 0x0020200
- /* Resets the codec interface to the IDLE state */
- void codec_reset(struct mga_dev *mga) {
- writel(VI_CMDCMPL, mga->ctrl + VICLEAR);
- writeb(0, mga->ctrl + CODECCTL);
- /* I repeat it twice per p. 4-110 of the G_4_00 HB */
- writeb(codecen, mga->ctrl + CODECCTL);
- writeb(codecen, mga->ctrl + CODECCTL);
- /* pulse recovery width (only usefull during bistream transfer
- if I understand correctly p.46 of the Handbook
- but we program the register anyway, as it belongs to
- the IDLE procedure referenced in the G400 manual */
- writeb((0<<4), mga->ctrl + CODECCTL + 1);
- RESET_CODEC_CMD_PTR;
- }
- /* Plays with the MISCCTL part of the codec interface
- Used to reset the actual CODEC chip connected to the MISC lines
- of the interface.
- */
- void codec_miscctl(struct mga_dev *mga, u8 and, u8 or) {
- /* we must be in IDLE (or COMP/DECOMP) for this to work p. 4-89)
- p. 4-92 states that MISC[2] is connected to EOI (?) when the CODEC Interface
- is enabled. So it seems that we can bang on these 2 bits too... */
- codec_reset(mga);
- writeb((readb(mga->ctrl + CODECMISCCTL) & and) | or, mga->ctrl + CODECMISCCTL);
- }
- void mga_extrst(struct mga_dev *mga, u8 activate) {
- u8 prev = readb(mga->ctrl + RST);
- if (activate)
- writeb(prev | 2, mga->ctrl + RST);
- else
- writeb(prev & ~2, mga->ctrl + RST);
- }
- int codec_miscctl_func1(struct mga_dev *mga, u8 param) {
- writeb(readb(mga->ctrl + CODECCTL) | codecen, mga->ctrl + CODECCTL);
- writeb(readb(mga->ctrl + CODECMISCCTL) & ~param, mga->ctrl + CODECMISCCTL);
- writeb(readb(mga->ctrl + CODECCTL) & ~codecen, mga->ctrl + CODECCTL);
- writeb(XGENIOCTRL, mga->ctrl + PALWTADD);
- writeb(readb(mga->ctrl + X_DATAREG) & ~0x40, mga->ctrl + X_DATAREG);
- writeb(XGENIODATA, mga->ctrl + PALWTADD);
- if (readb(mga->ctrl + X_DATAREG) & 0x40)
- return 0;
- else
- return 1;
- }
- int codec_miscctl_func2(struct mga_dev *mga) {
- writeb(readb(mga->ctrl + CODECCTL) | codecen, mga->ctrl + CODECCTL);
- writeb(readb(mga->ctrl + CODECMISCCTL) | 0x40, mga->ctrl + CODECMISCCTL);
- writeb(readb(mga->ctrl + CODECMISCCTL) & ~0x40, mga->ctrl + CODECMISCCTL);
- writeb(readb(mga->ctrl + CODECCTL) & ~codecen, mga->ctrl + CODECCTL);
- return 1;
- }
- int codec_I34_reset(struct mga_dev *mga) {
- codec_miscctl(mga, 0x00, 0x00);
- codec_miscctl(mga, 0x00, 0x03);
- codec_miscctl(mga, 0x00, 0x03);
- codec_miscctl(mga, ~0x0f, 0x07);
- mdelay(10);
- codec_miscctl(mga, ~0x0f, 0x03);
- mdelay(1);
- codec_miscctl(mga, ~0x0f, 0x07);
- codec_miscctl(mga, ~0x0f, 0x07);
- mdelay(100);
- codec_miscctl(mga, ~0x0f, 0x0f);
- mdelay(1);
- codec_miscctl(mga, ~0x0f, 0x07);
- mdelay(200);
- return 0;
- }
- /* Adds a READ command to the command buffer */
- void codec_read(struct mga_dev *mga, u8 reg) {
- /* duplicate reads because we're talking on an 8 bit bus */
- writel(CODEC_CMD(2, 0, 0, reg, 1), mga->codeccmd);
- writel(0, mga->codeccmd+4);
- mga->codeccmd += 8;
- }
- /* Adds a WRITE command to the command buffer */
- void codec_write(struct mga_dev *mga, u8 reg, u16 data) {
- u8 b;
- /* per p. 44 of the Zoran HB : */
- /* 2 consecutive byte accesses to the same address */
- writel(CODEC_CMD(2, 0, 0, 0, 0), mga->codeccmd);
- writel(0, mga->codeccmd+4);
- mga->codeccmd += 8;
- /*#ifdef __LITTLE_ENDIAN
- b = (data>>8) & 0xFF;
- writew(CODEC_WRITE(reg, b), mga->codeccmd);
- b = data & 0xFF;
- writew(CODEC_WRITE(reg, b), mga->codeccmd+2);
- #else
- */
- /* m.s. byte first */
- b = data & 0xFF;
- writew(CODEC_WRITE(reg, b), mga->codeccmd);
- b = (data>>8) & 0xFF;
- writew(CODEC_WRITE(reg, b), mga->codeccmd+2);
- writel(0, mga->codeccmd+4);
- mga->codeccmd += 8;
- // watch out the command buffer : we only have 512 bytes to play with !
- if ((mga->codeccmd - mga->codecaddr - 0x0020000) > 500) {
- dprintk("mgavideo: flushing codec command buffer...n");
- codec_exec(mga);
- }
- }
- /* Triggers execution of the command buffer
- We automatically add a dummy read command with the STOP bit enabled
- to terminate the instruction chain
- */
- void codec_exec(struct mga_dev *mga) {
- /* push a dummy command with the STOP bit enabled */
- writel(CODEC_CMD(2, 0, 1, 0x7, 1), mga->codeccmd);
- writel(0, mga->codeccmd+4);
- mga->codeccmd += 8;
-
- /* p. 3-68 of the MGA HandBook : it's not mentionned but we need not shift the addr
- by 3 bits. Instead it's placed directly from bit 0 onward, but bits 0-7 are nulls
- because we are Kb aligned */
- writel(((mga->codecaddr - (u32)mga->fb) & ~0x03), mga->ctrl + CODECADDR);
- RESET_CODEC_DATA_PTR;
- writel(0, mga->codecdata); writel(0, mga->codecdata+4);
- writel(0, mga->codecdata+8); writel(0, mga->codecdata+12);
- writel(0, mga->codecdata+16); writel(0, mga->codecdata+20);
- /* WARNING: it's the right combination : I've been blocked by those 2 bits for too long ! */
- codec_reset(mga);
- writeb(codecen | cmdexectrig, mga->ctrl + CODECCTL);
- /* give time to the Codec Interface do actually do its job */
- udelay(6);
- // if (!(_mgaread(mga, VSTATUS) & 0x02)) {
- // dprintk("mgavideo: warning no cmdcmpl after codec command...n");
- // }
- // else {
- // _mgawrite(mga, VICLEAR, 0x02);
- // }
- }
- /* Retrieves a word from the data buffer */
- u16 codec_getw(struct mga_dev *mga) {
- u16 data;
- data = readw(mga->codecdata);
- /*#ifdef __LITTLE_ENDIAN
- data = __swab16(data);
- #endif
- */
- #ifdef BYTEORDERHACK
- if (mga->little_endian_codec)
- data = __swab16(data);
- #endif
- mga->codecdata += 8;
- return data;
- }
- /* dumps the content of the codec interface buffers */
- void dump_codec_cmdbuffer(struct mga_dev *mga) {
- RESET_CODEC_CMD_PTR;
- dprintk("mgavideo: Command buffer:n");
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codeccmd+4), readl(mga->codeccmd));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codeccmd+12), readl(mga->codeccmd+8));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codeccmd+20), readl(mga->codeccmd+16));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codeccmd+28), readl(mga->codeccmd+24));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codeccmd+36), readl(mga->codeccmd+32));
- dprintk("mgavideo: Data buffer:n");
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codecdata+4), readl(mga->codecdata));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codecdata+12), readl(mga->codecdata+8));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codecdata+20), readl(mga->codecdata+16));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codecdata+28), readl(mga->codecdata+24));
- dprintk("mgavideo: 0x%8.8x%8.8xn", readl(mga->codecdata+36), readl(mga->codecdata+32));
- }
- static void
- mgacodec_and_or_codecctl(struct codec *codec, u16 and, u16 or)
- {
- int codecctl;
- struct mga_dev *mga;
- mga = codec->private;
- codecctl = (mga->codecctl_shadow & and) | or;
- mga->codecctl_shadow = codecctl;
- _mgawritew(mga, CODECCTL, codecctl);
- }
- static void
- mgacodec_and_or_codecmisc(struct codec *codec, u16 and, u16 or)
- {
- int codecmisc;
- struct mga_dev *mga;
- mga = codec->private;
- codecmisc = (mga->codecmisc_shadow & and) | or;
- mga->codecmisc_shadow = codecmisc;
- _mgawriteb(mga, CODECCTL+3, codecmisc);
- }
- static int
- mgacodec_execute_command(struct codec *codec)
- {
- int i;
- int status;
- struct mga_dev *mga;
- mga = codec->private;
- /* tell the system where memory buffer for zr36060 exists */
- _mgawrite(mga, CODECADDR, (mga->host_interface_base & ~0x03) | 0x01);
- if (mga->codecctl_shadow & VC_TRANSEN) {
- printk("wait for transfor to stopn");
- mgacodec_and_or_codecctl(codec, ~(VC_TRIG | VC_TRANSEN), 0);
- for(i = 1024 * 1024, status = _mgaread(mga, VSTATUS);
- (status & VS_STALLED) == 0 && i--;
- status = _mgaread(mga, VSTATUS)) ;
- printk("transfer stoped status %x VS_STALLED %xn", status, VS_STALLED);
- }
- /* remove any pending command complete */
- _mgawriteb(mga, VICLEAR, VI_CMDCMPL);
- codec->state = ZR_WRITE_STATE;
- /* start codec command */
- mgacodec_and_or_codecctl(codec, ~0x00, VC_TRIG);
- /* wait for codec command to complete */
- for(i = 4096, status = _mgareadb(mga, VSTATUS);
- (status & VS_STALLED) == 0 && i--;
- status = _mgareadb(mga, VSTATUS)) ;
- /* Ack the command complete interrupt */
- _mgawriteb(mga, VICLEAR, VI_CMDCMPL);
- codec->state = ZR_IDLE_STATE;
- mga->codec_offset = 0;
- if (status & VI_CMDCMPL)
- return 0;
- printk("mgavideo: no command complete on command 0x%x status 0x%xn",
- readw(mga->command_base), status);
- return 1;
- }
- static int
- mgacodec_read_memory(struct codec *codec, void *ptr, int mem, int size)
- {
- int last_high;
- int last_read;
- int last_exec;
- int i;
- int j;
- char *buffer;
- struct mga_dev *mga;
- mga = codec->private;
- buffer = ptr;
- last_high = -1;
- last_read = 0;
- last_exec = 0;
- dprintk("mgavideo: read %d bytes to memory %xn", size, mem);
- for(i=0; i < size; i++, mem++) {
- if (mga->codec_offset > (512 - 32)) {
- if (i > 0) {
- writew(0x8201 | (3 << 10),
- mga->command_base + last_read);
- }
- if (mgacodec_execute_command(codec)) {
- printk("mgavideo: Codec read buffer errorn");
- return -1;
- }
- for(j = last_exec; j < i; j++) {
- *buffer++ = readb(mga->read_base +
- (j - last_exec) * 8);
- }
- last_exec = i;
- }
- writew(0x0002, mga->command_base + mga->codec_offset);
- mga->codec_offset += 8;
- if (last_high != (mem >> 8)) {
- writew((mem >> 8) | 0x0100,
- mga->command_base + mga->codec_offset);
- mga->codec_offset += 2;
- }
- writew((mem & 0xff) | 0x0200,
- mga->command_base + mga->codec_offset);
- mga->codec_offset += 2;
- mga->codec_offset = (mga->codec_offset & ~7) + 8;
- writew(0x8001 | (3 << 10),
- mga->command_base + mga->codec_offset);
- last_read = mga->codec_offset;
- mga->codec_offset += 8;
- }
- if (last_read > 0) {
- writew(0x8201 | (3 << 10), mga->command_base + last_read);
- }
- if (mgacodec_execute_command(codec)) {
- printk("mgavideo: Codec read buffer errorn");
- return -1;
- }
- for(i=last_exec; i < size; i++) {
- *buffer++ = readb(mga->read_base + (i - last_exec) * 8);
- }
- return 0;
- }
- static int
- mgacodec_write_memory(struct codec *codec, void *mem, int start_reg, int length)
- {
- int offset;
- int count;
- int last_high;
- char *buffer;
- struct mga_dev *mga;
- mga = codec->private;
- buffer = mem;
- offset = (int)mga->command_base + 8;
- count = 0;
- last_high = -1;
- dprintk("mgavideo writing %d bytes to memory %xn",
- length, start_reg);
- while(length--) {
- if (last_high != (start_reg >> 8)) {
- last_high = start_reg >> 8;
- writew((start_reg >> 8) | 0x0100, offset);
- offset += 2;
- count++;
- }
-
- writew((start_reg++ & 0xff) | 0x0200, offset);
- writew((*buffer++ & 0xff) | 0x0300, offset+2);
- offset+= 4;
- count += 2;
- if (count > 250) {
- writew(count | 0x200, mga->command_base);
- if (mgacodec_execute_command(codec)) {
- printk("mgavideo: Codec write buffer errorn");
- return -1;
- }
- offset = (int)mga->command_base + 8;
- count = 0;
- }
- }
- if (count) {
- writew(count | 0x200, mga->command_base);
- if (mgacodec_execute_command(codec)) {
- printk("mgavideo: Codec write buffer errorn");
- return -1;
- }
- }
- return 0;
- }
- static int
- mgacodec_zr6060_start(struct codec *codec)
- {
- struct mga_dev *mga;
- mga = codec->private;
- _mgawrite(mga, CODECHOSTPTR, 64 * 1024);
- mgacodec_and_or_codecctl(codec, 0x4f, 0x4b);
- return 0;
- }
- static int
- mgacodec_zr36060_reset(struct codec *codec)
- {
- struct mga_dev *mga;
- mga = codec->private;
- /* reset the codec interface engine */
- mgacodec_and_or_codecctl(codec, 0x00, 0x00);
- mgacodec_and_or_codecctl(codec, 0x00, 0x03);
- mgacodec_and_or_codecctl(codec, 0x00, 0x03);
- /* pulse the reset line */
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x07);
- mdelay(10);
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x03);
- mdelay(1);
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x07);
- /* pulse the sleep line */
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x07);
- mdelay(100);
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x0f);
- mdelay(1);
- mgacodec_and_or_codecmisc(codec, ~0x0f, 0x07);
- mdelay(200);
- /* tell the system where memory buffer for zr36060 exists */
- _mgawrite(mga, CODECADDR, (mga->host_interface_base & ~0x03) | 0x01);
- return 0;
- }
- /****************************************************************************
- * mga i2c bus interface
- ****************************************************************************/
- static void _mgai2c_attach( struct i2c_bus* bus, int id )
- {
- struct mga_dev* mga = (struct mga_dev*)bus->data;
- dprintk( "mgavideo: i2c device attach: %dn", id );
- switch( id )
- {
- case I2C_DRIVERID_MSP3400:
- mga->hasaudio = 1;
- break;
- case I2C_DRIVERID_TUNER:
- mga->hastuner = 1;
- break;
- case I2C_DRIVERID_KS0127:
- mga->hasdecoder = 1;
- break;
- }
- }
- static void _mgai2c_detach( struct i2c_bus* bus, int id )
- {
- struct mga_dev* mga = (struct mga_dev*)bus->data;
- dprintk( "mgavideo: i2c device detach: %dn", id );
- switch( id )
- {
- case I2C_DRIVERID_MSP3400:
- mga->hasaudio = 0;
- break;
- case I2C_DRIVERID_TUNER:
- mga->hastuner = 0;
- break;
- case I2C_DRIVERID_KS0127:
- mga->hasdecoder = 0;
- break;
- }
- }
- static void _mgai2c_setlines( struct i2c_bus* bus, int ctrl, int data )
- {
- struct mga_dev* mga = (struct mga_dev*)bus->data;
- if( ctrl )
- {
- writeb( XGENIOCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) & ~SCL, mga->ctrl + X_DATAREG );
- }
- else
- {
- writeb( XGENIODATA, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) & ~SCL, mga->ctrl + X_DATAREG );
- writeb( XGENIOCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) | SCL, mga->ctrl + X_DATAREG );
- }
- if( data )
- {
- writeb( XGENIOCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) & ~SDA, mga->ctrl + X_DATAREG );
- }
- else
- {
- writeb( XGENIODATA, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) & ~SDA, mga->ctrl + X_DATAREG );
- writeb( XGENIOCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) | SDA, mga->ctrl + X_DATAREG );
- }
- udelay( I2C_DELAY );
- }
- static int _mgai2c_getdataline( struct i2c_bus* bus )
- {
- struct mga_dev* mga = (struct mga_dev*)bus->data;
- writeb( XGENIOCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) & ~SDA, mga->ctrl + X_DATAREG );
- writeb( XGENIODATA, mga->ctrl + PALWTADD );
- return ( readb( mga->ctrl + X_DATAREG ) & SDA )?1:0;
- }
- /****************************************************************************
- * private api : internal interface to the mga's video subsystem
- ****************************************************************************/
- /****************************************************************************
- * mgavideo api : public interface to the mga's video subsystem
- ****************************************************************************/
- /* component device control */
- void mgavideo_tuner( struct mga_dev* mga, unsigned int cmd, void* arg )
- {
- if( mga == NULL )
- return;
- if( mga->hastuner )
- i2c_control_device( &(mga->i2c), I2C_DRIVERID_TUNER, cmd, arg );
- }
- void mgavideo_audio( struct mga_dev* mga, unsigned int cmd, void* arg )
- {
- if( mga == NULL )
- return;
- if( mga->hasaudio )
- i2c_control_device( &(mga->i2c), I2C_DRIVERID_MSP3400, cmd, arg );
- }
- void mgavideo_decoder( struct mga_dev* mga, unsigned int cmd, void* arg )
- {
- if( mga == NULL )
- return;
- if( mga->hasdecoder )
- i2c_control_device( &(mga->i2c), I2C_DRIVERID_KS0127, cmd, arg );
- }
- void mgavideo_zr36060_reset(struct mga_dev* mga)
- {
- // dbarth:
- // is it still usefull to have that here. It creates a dependency with mgavideo
- // and complicates module loading/unloading
- // Please tell me
- #ifdef NEVER
- zr36060_attach(&mga->zr36060);
- #endif
- }
- int mgavideo_querycaps( struct mga_dev* mga )
- {
- int caps = 0;
- if( mga == NULL )
- return 0;
- if( mga->hastuner )
- caps |= MGAVIDEO_HAS_TUNER;
- if( mga->hasaudio )
- caps |= MGAVIDEO_HAS_AUDIO;
- if( mga->hasdecoder )
- caps |= MGAVIDEO_HAS_DECODER;
- return caps;
- }
- u8* mgavideo_lock_video( struct mga_dev* mga )
- {
- mga->locked = mga->status;
- if( mga->status & VS_FIELD ) {
- return mga->fb + mga->vin_addr1;
- } else {
- return mga->fb + mga->vin_addr0;
- }
- }
- void mgavideo_unlock_video( struct mga_dev* mga )
- {
- mga->locked = 0;
- }
- static void _detect_tvt( struct mga_dev* mga )
- {
- int msp, tuner_addr, tuner;
- if( mga->hastuner && mga->hasaudio ) {
- mgavideo_tuner( mga, TUNER_GET_ADDRESS, &tuner_addr );
- mgavideo_audio( mga, MSP_GET_UNIT, &msp );
- tuner = TUNER_ABSENT;
- switch( tuner_addr ) {
- case 0xc0:
- /* Samsung MULTI PAL - unsupported by tuner.c? */
- break;
- case 0xc2:
- if( (msp&0xff) == 0x07 ) { /* Usa audio */
- tuner = TUNER_PHILIPS_NTSC;
- } else {
- /* Samsung SECAM - unsupported by tuner.c? */
- }
- break;
-
- case 0xc4:
- tuner = TUNER_PHILIPS_PAL_I;
- break;
- case 0xc6:
- if( (msp&0xff) == 0x07 ) { /* Usa audio */
- /* Samsung NTSC - unsupported by tuner.c? */
- } else {
- tuner = TUNER_PHILIPS_SECAM;
- }
- }
-
- mgavideo_tuner( mga, TUNER_SET_TYPE, &tuner );
- }
- }
- /****************************************************************************
- * interrupt processing
- ****************************************************************************/
- static void mgavideo_vsync(struct mga_dev *mga)
- {
- /* increment frame counter */
- mga->grabbed++;
- /* We may have change the pitch or base address */
- if (mga->status & VS_FIELD) {
- /* program even field data */
- _mgawrite( mga, VINCTL0, ( VIN_ON | VBI_RAW | (mga->vinpitch >> 2) << 3) );
- } else {
- /* program odd field data */
- _mgawrite( mga, VINCTL1, ( VIN_ON | VBI_RAW | (mga->vinpitch >> 2) << 3) );
- }
- #ifdef NEVER
- zr36060_compress_image(&mga->zr36060);
- {
- struct timeval curr;
- do_gettimeofday(&curr);
- dprintk("mgavideo: interrupt status=%x frames e=%d o=%d time: %d:%dn", mga->status,
- mga->req_even, mga->req_odd, curr.tv_sec, curr.tv_usec);
- }
- #endif
-
- if( !(mga->locked & ( VS_VIDEO | VS_RAWVBI | VS_SLICEDVBI ) ) ) {
- /* if no video fields are locked, program the next window
- * based on what window was just grabbed */
- #ifdef NEVER
- _mgawrite( mga, VINNEXTWIN, (mga->status&VS_FIELD)?0:1 );
- #else
- _mgawrite( mga, VINNEXTWIN, (mga->status&VS_FIELD)?1:0 );
- #endif
- /* queue bottom half if present, and requested */
- if( mga->tqnode_dpc.routine ) {
- if (( mga->req_even && !( mga->status & VS_FIELD ))
- || ( mga->req_odd && ( mga->status & VS_FIELD ))) {
- queue_task(&mga->tqnode_dpc, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- } else {
- #ifdef NEVER
- printk("frame not wanted odd %d even %d status= %xn",
- mga->req_even, mga->req_odd, mga->status);
- #endif
- }
- }
- } else {
- /* otherwise, program the next window based on what field
- * is locked */
- #ifdef NEVER
- _mgawrite( mga, VINNEXTWIN, (mga->status&VS_FIELD)?0:1 );
- #else
- _mgawrite( mga, VINNEXTWIN, (mga->status&VS_FIELD)?1:0 );
- #endif
- #ifdef NEVER
- printk("frame buffer lockedn");
- #endif
- }
- }
- static void interrupt_hw(int irq, void *v, struct pt_regs *regs)
- {
- struct mga_dev* mga = (struct mga_dev*)v;
- if (mga == NULL)
- return;
- /* read status register */
- mga->status = _mgaread( mga, VSTATUS );
- if (mga->status & VI_IVSYNC) {
- mgavideo_vsync(mga);
- _mgawrite( mga, VICLEAR, VI_IVSYNC );
- }
- if (mga->status & VI_CMDCMPL) {
- printk("mgavideo: command complete pendingn");
- #ifdef NEVER
- zr36060_interrupt(&mga->zr);
- _mgawrite( mga, VICLEAR, VI_CMDCMPL);
- #endif
- }
- if (mga->status & VI_BLVL) {
- printk("mgavideo: buffer level pendingn");
- _mgawrite( mga, VICLEAR, VI_BLVL);
- }
- if (mga->status & VI_EOI) {
- printk("mgavideo: codec decompression end of image pendingn");
- _mgawrite( mga, VICLEAR, VI_EOI);
- }
- }
- /* enable interrupts */
- void mgavideo_ivsync_enable( struct mga_dev* mga, int en )
- {
- u32 istat;
- if( mga == NULL )
- return;
- dprintk( "mgavideo: %sable IVSYNC interruptn", en?"en":"dis" );
- _mgawrite( mga, VICLEAR, VI_IVSYNC );
- istat = _mgaread( mga, VIEN );
- _mgawrite( mga, VIEN, en?(istat|VI_IVSYNC):(istat&~VI_IVSYNC) );
- }
- /* register a routine to be called for each frame */
- void mgavideo_register_bh( struct mga_dev* mga, int req_even, int req_odd,
- void(*routine)(void*), void* data )
- {
- mga->req_even = req_even;
- mga->req_odd = req_odd;
- mga->tqnode_dpc.next = NULL;
- mga->tqnode_dpc.sync = 0;
- mga->tqnode_dpc.routine = routine;
- mga->tqnode_dpc.data = data;
- }
- /*
- * reset the the hardware for dma cap for new size. Also need to
- * update the ks0127 to scale for new size.
- */
- void mgavideo_set_dims(struct mga_dev *mga, int width, int height)
- {
- mgavideo_decoder( mga, KS0127_SET_WIDTH, &width);
- mga->vinpitch = width;
- #ifdef NEVER
- mgavideo_decoder( mga, KS0127_SET_HEIGHT, &height);
- #endif
- }
- /****************************************************************************
- * back-end scaler
- ****************************************************************************/
- void* mgavideo_get_base( struct mga_dev* mga )
- {
- return mga->fb;
- }
- void mgavideo_set_window( struct mga_dev* mga, int x, int y, int w, int h )
- {
- _mgawrite( mga, BESHCOORD, (x<<16) | (x+w-1) );
- _mgawrite( mga, BESVCOORD, (y<<16) | (y+h-1) );
- _mgawrite( mga, BESHISCAL, (_VINWID<<16) / w);
- _mgawrite( mga, BESVISCAL, (_VINHGT<<16) / h);
- }
- void mgavideo_set_colorkey( struct mga_dev* mga, int r, int g, int b )
- {
- /* Activate the colorkey mode */
- writeb( XKEYOPMODE, mga->ctrl + PALWTADD );
- writeb( 1, mga->ctrl + X_DATAREG );
- writeb( XCOLMSK0RED, mga->ctrl + PALWTADD );
- writeb( 0xff, mga->ctrl + X_DATAREG );
- writeb( XCOLMSK0GREEN, mga->ctrl + PALWTADD );
- writeb( 0xff, mga->ctrl + X_DATAREG );
- writeb( XCOLMSK0BLUE, mga->ctrl + PALWTADD );
- writeb( 0xff, mga->ctrl + X_DATAREG );
- writeb( XCOLKEY0RED, mga->ctrl + PALWTADD );
- writeb( r, mga->ctrl + X_DATAREG );
- writeb( XCOLKEY0GREEN, mga->ctrl + PALWTADD );
- writeb( g, mga->ctrl + X_DATAREG );
- writeb( XCOLKEY0BLUE, mga->ctrl + PALWTADD );
- writeb( b, mga->ctrl + X_DATAREG );
- }
- void mgavideo_set_overlay( struct mga_dev* mga )
- {
- /* Activate the overlay mode */
- writeb( XKEYOPMODE, mga->ctrl + PALWTADD );
- writeb( 0, mga->ctrl + X_DATAREG );
- }
- void mgavideo_preview_enable( struct mga_dev* mga, int en )
- {
- /* Activate scaler */
- _mgawrite( mga, BESCTL, en?0x00000007:0x00000000 );
- /* Activate automatic switching of windows
- * This is for testing only
- */
- _mgawrite( mga, VINNEXTWIN, en?2:0 );
- }
- /****************************************************************************
- * initialization
- ****************************************************************************/
- static void _mgavideo_init( struct mga_dev* mga )
- {
- writeb( XMISCCTRL, mga->ctrl + PALWTADD );
- writeb( readb( mga->ctrl + X_DATAREG ) | 0x06, mga->ctrl + X_DATAREG );
- /* detect tv-tuner */
- _detect_tvt( mga );
- /* enable video-in */
- _mgawrite( mga, VINCTL, 0x0101ab01 );
- /* just in case, clear video interrupt */
- _mgawrite( mga, VICLEAR, VI_IVSYNC );
- /* setup video window 0 */
- _mgawrite( mga, VINCTL0, ( VIN_ON | VBI_RAW | (mga->vinpitch >> 2) << 3) );
- _mgawrite( mga, VBIADDR0, mga->vbi_addr0);
- _mgawrite( mga, VINADDR0, mga->vin_addr0);
- /* setup video window 1 */
- _mgawrite( mga, VINCTL1, ( VIN_ON | VBI_RAW | (mga->vinpitch >> 2) << 3) );
- _mgawrite( mga, VBIADDR1, mga->vbi_addr1);
- _mgawrite( mga, VINADDR1, mga->vin_addr1);
- /* setup backend scaler */
- _mgawrite( mga, BESPITCH, mga->vinpitch & (~3));
- _mgawrite( mga, BESHSRCLST, (_VINWID-1)<<16 );
- _mgawrite( mga, BESHSRCST, 0<<14 );
- _mgawrite( mga, BESHSRCEND, (_VINWID * 4 -1)<<14 );
- _mgawrite( mga, BESV1SRCLST, 255 );
- _mgawrite( mga, BESV2SRCLST, 255 );
- _mgawrite( mga, BESA1ORG, mga->vin_addr0 );
- _mgawrite( mga, BESA2ORG, mga->vin_addr1 );
- _mgawrite( mga, BESB1ORG, mga->vin_addr0 );
- _mgawrite( mga, BESB2ORG, mga->vin_addr1 );
- /* register interrupt routine */
- if( mga->irq ) {
- if( request_irq( mga->irq, interrupt_hw, SA_SHIRQ,
- mga->name, mga ) < 0 ) {
- dprintk( "mgavideo: Denied IRQ %dn", mga->irq );
- mga->irq_status = 0;
- } else {
- mga->irq_status = mga->irq;
- }
- }
- }
- #define NBOARDS 4
- struct mga_dev mgavideo_dev[NBOARDS];
- /* HACK to get the MGA struct.
- the 'mgavideo_get' routine cannot handle multiple use
- of the same board anyway...
- */
- struct mga_dev* mgavideo_get_codec() {
- if (&mgavideo_dev[0] != NULL)
- return &mgavideo_dev[0];
- else
- return NULL;
- }
- /* find all mga adapters */
- struct mga_dev* mgavideo_get( void )
- {
- int i;
- struct mga_dev* mga;
- for( i=0; i<NBOARDS; i++ )
- {
- mga = &mgavideo_dev[i];
- if( !mga->inuse && (mga->ctrl != NULL) )
- {
- dprintk( "mgavideo: acquire video device %xn", i );
- mga->inuse++;
- MOD_INC_USE_COUNT;
- _mgavideo_init( mga );
- return mga;
- }
- }
- return NULL;
- }
- /* release a mga adapter that is not needed anymore */
- void mgavideo_release( struct mga_dev* mga )
- {
- if( mga == NULL )
- return;
- if( mga->ctrl )
- {
- /* clear any pending interrupt */
- _mgawrite( mga, VICLEAR, VI_IVSYNC );
- /* disable video interrupt */
- _mgawrite( mga, VIEN, _mgaread( mga, VIEN ) & ~VI_IVSYNC );
- /* disable video-in */
- _mgawrite( mga, VINCTL, 0x0101ab00 );
- /* disable (temp) backend scaler */
- mgavideo_preview_enable( mga, 0 );
- /* Turn off the zr36060 */
- #ifdef NEVER
- zr36060_deattach(&mga->zr);
- #endif
- /* un-register isr */
- if( mga->irq_status ) {
- free_irq( mga->irq_status, mga );
- mga->irq_status = 0;
- }
- MOD_DEC_USE_COUNT;
- mga->inuse--;
- dprintk( "mgavideo: release video devicen" );
- printk( "mgavideo: grabbed %d total framesn", mga->grabbed );
- }
- }
- /****************************************************************************
- * linux kernel module api
- ****************************************************************************/
- #ifdef MODULE
- int init_module( void )
- #else
- int mgavideo_init( void )
- #endif
- {
- int found = 0;
- struct pci_dev* dev;
- struct mga_dev* mga;
- u32 mem;
- u32 addr = 0;
- dprintk( "mgavideo: Looking for boards...n" );
- /* find the next MGA G100 or G200 */
- for( dev = pci_devices; dev != NULL; dev = dev->next )
- {
- if (dev->class != PCI_CLASS_NOT_DEFINED_VGA &&
- ((dev->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
- continue;
- if (PCI_FUNC(dev->devfn) != 0)
- continue;
- /* ignore non-mga adapters */
- if (dev->vendor != PCI_VENDOR_ID_MATROX)
- continue;
- /* ignore non-gseries adapters */
- if (dev->device != PCI_DEVICE_ID_MATROX_G200_PCI &&
- dev->device != PCI_DEVICE_ID_MATROX_G200_AGP &&
- dev->device != PCI_DEVICE_ID_MATROX_G100_MM &&
- dev->device != PCI_DEVICE_ID_MATROX_G100_AGP)
- continue;
- /* the device is cool. set up a context for it */
- mga = &mgavideo_dev[found];
- memset( mga, 0, sizeof( *mga ) );
- mga->device = dev->device;
- mga->inuse = 0;
- mga->irq = dev->irq;
- dprintk( "mgavideo: mapping fb memory...n" );
- /* read and map the frame buffer and control aperture */
- addr = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
- mga->fb = ioremap( addr, 0x800000 );
- dprintk( "mgavideo: mapping ctrl memory...n" );
- addr = dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
- mga->ctrl = ioremap( addr, 0x4000 );
- dprintk( "mgavideo: Okn" );
- /* setup address for video in memory */
- mem = memsize - 1l;
- mem = (mem - _VIN_WINDOW) & VINADDRx_MASK;
- mga->vin_addr0 = mem;
- mem = (mem - _VIN_WINDOW) & VINADDRx_MASK;
- mga->vin_addr1 = mem;
- mem = (mem - _VBI_WINDOW) & VBIADDRx_MASK;
- mga->vbi_addr0 = mem;
- mem = (mem - _VBI_WINDOW) & VBIADDRx_MASK;
- mga->vbi_addr1 = mem;
- /* init memory for zr36060 */
- mem = (mem - (257 * 1024)) & ~0x3ff;
- mga->host_interface_base = mem;
- mga->interface_base = (u8 *)(mga->fb) + mem;
- mga->command_base = (u8 *)(mga->fb) + (mem + 256 * 1024);
- mga->read_base = mga->command_base + 512;
- mga->codec_offset = 0;
- /* Default pitch for mga */
- mga->vinpitch = 704;
- mga->vin_field = _VIN_FIELD_EVEN;
- /* fill in zr36060 register address */
- mga->zr36060.codec_id = ZR36060_ID;
- mga->zr36060.private = mga;
- mga->zr36060.memory_size = 8;
-
- mga->zr36060.codec_read_memory = mgacodec_read_memory;
- mga->zr36060.codec_write_memory = mgacodec_write_memory;
- mga->zr36060.codec_reset = mgacodec_zr36060_reset;
- mga->zr36060.codec_start = mgacodec_zr6060_start;
- /*******************************************/
- /* Setup addresses for the Codec Interface */
- /*******************************************/
- /* p. 3-68 of the MGA HandBook : the Codec Addr must be aligned
- on a 1Kb boundary */
- mga->codecaddr = ((u32)mga->fb + 0x0004000) & ~0xFF;
- /* reset the device */
- _mgawrite( mga, VINCTL, 0x0101ab00 );
- /* setup the i2c */
- sprintf( mga->i2c.name, "mga%d", found );
- mga->i2c.id = I2C_BUSID_MGA;
- mga->i2c.data = mga;
- #if LINUX_VERSION_CODE >= 0x020100
- mga->i2c.bus_lock = SPIN_LOCK_UNLOCKED;
- #endif
- mga->i2c.attach_inform = _mgai2c_attach;
- mga->i2c.detach_inform = _mgai2c_detach;
- mga->i2c.i2c_setlines = _mgai2c_setlines;
- mga->i2c.i2c_getdataline = _mgai2c_getdataline;
- mga->i2c.i2c_read = NULL;
- mga->i2c.i2c_write = NULL;
- i2c_register_bus( &mga->i2c );
- sprintf( mga->name, "mgavideo%d", found );
- /* okay everything looks good */
- dprintk( "mgavideo: Found %s: device 0x%x irq %in", mga->name, mga->device, mga->irq );
-
- if( ++found >= NBOARDS )
- break;
- }
- if( !found )
- return -ENODEV;
- return 0;
- }
- #ifdef MODULE
- void cleanup_module( void )
- {
- int i;
- struct mga_dev* mga;
- for( i=0; i<NBOARDS; i++ )
- {
- mga = &mgavideo_dev[i];
- if( mga->ctrl )
- {
- i2c_unregister_bus( &mga->i2c );
- iounmap( (void*)mga->ctrl );
- iounmap((void*)mga->fb);
- }
- }
- }
- #endif