Logo Search packages:      
Sourcecode: lg-issue91 version File versions

pvcl.c

/*  Copyright (C) 2003 Cherry George Mathew <cherry@freeshell.org>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/version.h> 
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include "pvcard.h"
#include "pvcl.h" 
#include "pvproc.h"
#include <asm/io.h>
#include <asm/bitops.h>

/* const declarations and static allocations */

/* card ids ends with vendor id as marker. Number of cards is defined \
 * as MAX_CARDS. Will add PCI_DEVICE_ID_CIRRUS_5465 Later.
 */
const int clgd54xx_card_id[]={PCI_DEVICE_ID_CIRRUS_5480,\
                        PCI_DEVICE_ID_CIRRUS_5446,\
                        PCI_VENDOR_ID_CIRRUS};

/* Decided against kmalloc for the moment. Would probably be efficient
 * if we dealt with stuff like multiple cards, etc. not for the moment,
 * though.
 */


/* Default max screen size hardcoded to ???? */
static struct video_buffer vbuf_s = { 
};

static struct video_picture vpict_s;

/* TODO: Chroma keying.....Default _no_ chromakeying bcos xawtv has no
 *   support for it with V4L1. Someday.... Sigh ......*/

static struct video_window vwin_s = { 
/*    chromakey:  GD_CHROMA_KEY,  */
/*    flags:      VIDEO_WINDOW_CHROMAKEY   */
};

/* Tuner properties hardcoded. */
static struct video_tuner vtun_s = {
      name:        "Television",
      rangelow:    0,
      rangehigh:   0x7FFFFFFF,
      flags:       VIDEO_TUNER_PAL, 
      mode:        VIDEO_MODE_PAL
};

/* Single channel support at the moment. S-Video and Composite ignored. */
static struct video_channel vchan_s = {
      name:        "Television",
      tuners:      1,
      flags:       VIDEO_VC_TUNER | VIDEO_VC_AUDIO,
      type:        VIDEO_TYPE_TV,
      norm:        VIDEO_MODE_PAL
};

static struct gd_status_t dstat_s = { 
      vbuf_p:     &vbuf_s,
      vwin_p:     &vwin_s,
      vtun_p:     &vtun_s,
      vchan_p:    &vchan_s,
      vpict_p:    &vpict_s,
};

/* Initializing a new adapter named clgd54xx. Right now, we'll make do 
   with a static declaration. Not good enough for driving multiple cards.
*/


static struct clgd54xx_card clgd54xx_card_info = {
      spun_lock:    SPIN_LOCK_UNLOCKED,
      drv_stat_p:   &dstat_s,
      model:        PVCLPP_COMBO
};

static struct i2c_algo_bit_data clgd54xx_bitbang_adap = {
      data:         &clgd54xx_card_info,
      setsda:       gd54xx_setsda,
      setscl:       gd54xx_setscl,
      getsda:       gd54xx_getsda,
      getscl:       gd54xx_getscl,
      udelay:       16,
      mdelay:       10,
      timeout:      200,
};

static struct i2c_adapter clgd54xx_adap = {
      name:        "clgd54xx",

      /* Now make i2c_adapter->algo_data point to our 
       * i2c_algo_bit_data , ie; link adapter and algo.
       */

      id:          I2C_ALGO_BIT | I2C_HW_B_BT848,
      algo_data:   &clgd54xx_bitbang_adap,
};

/* variable declarations and initializations */

unsigned int debug = 0;
unsigned int re_entry = 0;

/* Adapter - Low level functions  */

/* Note:
 * 5480 and 5446B can use either MMIO or PIO
 * 5446A must use PIO
 * 5465 must use MMIO
 */

unsigned io_readb(unsigned port)
{
      vprintk("io_io_read on port %p\n", (char *) port);
      return inb(port);
}

void io_writeb(unsigned data, unsigned port)
{
      vprintk("io_io_write on port %p\n", (char *) port);
      outb(data, port);
} 

/***************  TODO: IMPLEMENT PCI MEM MAPPING *****************


unsigned m_io_readb_proc(unsigned port)
{
      vprintk("m_io_read on port %p\n", (char *) port);
      return readb(port);
}

void m_io_writeb_proc(unsigned data, unsigned port)
{
      vprintk("m_io_write on port %p\n", (char *) port);
      writeb(data, port);
}

*************************************************************************/
void gd_write_sr(struct clgd54xx_card *card_p,unsigned char datum,unsigned reg) 
{
      spin_lock_irqsave(&card_p->spun_lock, card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_SR_OFFSET); 
      io_writeb(datum, card_p->gd_io_base + GD_SR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock, card_p->spinflags);

}


void gd_write_gr(struct clgd54xx_card *card_p, unsigned char datum,unsigned reg) 
{ 
        spin_lock_irqsave(&card_p->spun_lock,card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_GR_OFFSET); 
      io_writeb(datum, card_p->gd_io_base + GD_GR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock,card_p->spinflags);

}

void gd_write_cr(struct clgd54xx_card *card_p, unsigned char datum,unsigned reg) 
{
        spin_lock_irqsave(&card_p->spun_lock, card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_CR_OFFSET);
      io_writeb(datum, card_p->gd_io_base + GD_CR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock,card_p->spinflags);

}

unsigned gd_read_sr(struct clgd54xx_card *card_p, unsigned reg) 
{
      unsigned value;
      spin_lock_irqsave(&card_p->spun_lock,card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_SR_OFFSET);
      value = io_readb(card_p->gd_io_base + GD_SR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock,card_p->spinflags);
      return value;
}

unsigned gd_read_gr(struct clgd54xx_card *card_p, unsigned reg)
{
      unsigned value;
        spin_lock_irqsave(&card_p->spun_lock, card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_GR_OFFSET);
      value = io_readb(card_p->gd_io_base + GD_GR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock,card_p->spinflags);
      return value;
}

unsigned gd_read_cr(struct clgd54xx_card *card_p, unsigned reg)
{
      unsigned value;
      spin_lock_irqsave(&card_p->spun_lock, card_p->spinflags);
      io_writeb(reg, card_p->gd_io_base + GD_CR_OFFSET); 
      value = io_readb(card_p->gd_io_base + GD_CR_OFFSET + 1);
      spin_unlock_irqrestore(&card_p->spun_lock, card_p->spinflags);
      return value;
}
 

void gd54xx_setsda (void *bit_adap_dat, int state)
{
      struct clgd54xx_card *data=bit_adap_dat;

      /* Switch on I2C interface */
      set_bit(6, &data->i2c_state);

      /* Set/Clear bit */ 
      state ? set_bit(1, &(data->i2c_state)) : clear_bit(1, &(data->i2c_state));

      gd_write_sr(data, data->i2c_state, 0x8);
}

void gd54xx_setscl (void *bit_adap_dat, int state)
{
      struct clgd54xx_card *data=bit_adap_dat;

      set_bit(6, &data->i2c_state);
      state ? set_bit(0, &(data->i2c_state)) : clear_bit(0, &(data->i2c_state));

      gd_write_sr(data, data->i2c_state, 0x8);
}

int gd54xx_getsda (void *bit_adap_dat)
{
      struct clgd54xx_card *data=bit_adap_dat;

      return (((data->i2c_state = gd_read_sr(data, 0x8)) >>7)&0x1);

      return 0;
}

int gd54xx_getscl (void *bit_adap_dat)
{
      struct clgd54xx_card *data=bit_adap_dat;
      return (((data->i2c_state = gd_read_sr(data, 0x8)) >>2)&0x1);
      return 0;
}

/* Adapter functions - high level */

int i2c_clgd54xx_init_adapter(struct clgd54xx_card *card_p, 
                        struct i2c_adapter * adap,
                        struct i2c_algo_bit_data * bitadap)
{

      /* Let's initialize some of the data structures.
       * First plug in card adapter and card bit bang algo
       * into card info.
       */

      card_p->clgd54xx_adapter_p = adap;
      card_p->clgd54xx_bitbang_adapter_p = bitadap;

      return      i2c_bit_add_bus(card_p->clgd54xx_adapter_p);

}

int i2c_clgd54xx_cleanup_adapter(struct clgd54xx_card *card_p){

      return i2c_bit_del_bus(card_p->clgd54xx_adapter_p);
}

int i2c_clgd54xx_probe_card(struct clgd54xx_card *card_p)
{
      card_p->gd_io_base=0;
      
      /* Memory Mapped IO not supported at the moment.
       * This driver won't work for multiple cards.
       */
      return 0;
}

int i2c_clgd54xx_find_card(struct clgd54xx_card *card_p){
      
        struct pci_dev *dev = NULL;
      int loop_count=0;
      do{
            if ((dev = pci_find_device(clgd54xx_card_id[MAX_CARDS],clgd54xx_card_id[loop_count], dev))) {

                  printk(KERN_INFO
                         "pvcl: Found %s\n", dev->name);
                  card_p->clgd54xx_pci_dev_p = dev;
                  card_p->clgd54xx_pci_dev_id =
                        clgd54xx_card_id[loop_count];
                  
                  printk(KERN_INFO
                         "pvcl: Detected %dMB video ram.\n",
                         gd_count_ram(card_p));
                  
                  return 0;
            }
            loop_count++;
      } while(clgd54xx_card_id[loop_count]!=clgd54xx_card_id[MAX_CARDS]);

      printk(KERN_WARNING
             "pvcl: Sorry. Could not find a Cirrus Logic Chip.\n");
      return -ENODEV;

}


/*
 *  gd_count_ram() is hacked from gd5480.c from the xtv package.
 *  xtv is copyrighted to Itai Nahshon <nahshon@actcom.co.il>.
 *  Used with permission from the author.
 */


int
gd_count_ram(struct clgd54xx_card *card_p)
{
      int videoram = 1;
      int SR0F, SR17;

      unsigned short chip_type = card_p->clgd54xx_pci_dev_id;

      switch (chip_type) {
        case PCI_DEVICE_ID_CIRRUS_5446:
            videoram = 1;
      
            SR0F = gd_read_sr(card_p, 0x0F);
            SR17 = gd_read_sr(card_p, 0x17);
            if ((SR0F & 0x18) == 0x18) {
                  if(SR0F & 0x80) {
                        if(SR17 & 0x80)
                              videoram = 2;
                        else if(SR17 & 0x02)
                              videoram = 3;
                        else
                              videoram = 4;
                  }
                  else {
                        if((SR17 & 80) == 0)
                              videoram = 2;
                  }
            }
            break;
            
      case PCI_DEVICE_ID_CIRRUS_5480:
            videoram = 1;
            SR0F = gd_read_sr(card_p, 0x0F);
            if ((SR0F & 0x18) == 0x18) {  /* 2 or 4 MB */
                  videoram = 2;
                  if (SR0F & 0x80)  /* Second bank enable */
                        videoram = 4;
            }
            break;
            
      case PCI_DEVICE_ID_CIRRUS_5465:
            videoram = 4;
            break;
      }

      card_p->vram = videoram;
      return videoram;
}


int __init i2c_clgd54xx_init(struct clgd54xx_card *card_p,
                       struct i2c_adapter *adap,
                       struct i2c_algo_bit_data *bitadap)
{
      int ret_val;

      /* This adapter is non-re-entrant at the moment */

      if(re_entry) return -EBUSY;

      re_entry = 1;

      if( (ret_val = i2c_clgd54xx_find_card(card_p)) ){
            return ret_val;
      }
      
      if( (ret_val = i2c_clgd54xx_probe_card(card_p)) ){
            return ret_val;
      }
      
      if( (ret_val = i2c_clgd54xx_init_adapter(card_p, adap, bitadap)) ){
            return ret_val;
      }
      
      return ret_val;
}

int __init i2c_clgd54xx_cleanup(struct clgd54xx_card *card_p)
{
      re_entry=0;

      return i2c_clgd54xx_cleanup_adapter( card_p );
      
}

/* i2c client support */
void do_client_ioctl(struct file *file, unsigned int cmd, void *arg)
{
      struct clgd54xx_card  *card_p = file->private_data;
      struct i2c_adapter *adap = card_p->clgd54xx_adapter_p;
      
      int i;
      
        for (i = 0; i < I2C_CLIENT_MAX; i++) {
                if (NULL == adap->clients[i])
                        continue;
                if (NULL == adap->clients[i]->driver->command)
                        continue;
                adap->clients[i]->driver->command(
                                         adap->clients[i],cmd,arg);
        }

      
}

/* VGA support functions. */

/* gd_bit_copy() - used for copying data to/from VGA registers */

void gd_bit_copy(unsigned long * dest, int dest_start,  
             unsigned long * src, int src_start, int src_stop)
{
      for(; src_start<= src_stop; src_start++, dest_start++)
            {
                  if(test_bit(src_start, src))
                        set_bit(dest_start, dest);
                  else
                        clear_bit(dest_start, dest);
            }
                           
}

void gd_enable_window(struct clgd54xx_card * card_p)
{
      unsigned long CR3E, CR50, CR51, CR58, CR5C;

      CR3E = gd_read_cr(card_p, 0x3e);
      CR50 = gd_read_cr(card_p, 0x50);
      CR51 = gd_read_cr(card_p, 0x51);
      CR58 = gd_read_cr(card_p, 0x58);
      CR5C = gd_read_cr(card_p, 0x5c);

      /* Disable Teletext CR5C[7] = 0 */
      clear_bit(7,  &CR5C); 

/*    Capture all frames CR50[7], CR50[2], CR58[6] = 0,0,0 */

      clear_bit(7, &CR50); 
      clear_bit(2, &CR50); 
      clear_bit(6, &CR58); 
      
      /*    Set Capture input to VPORT CR50[1:0] = 11  */

      set_bit(0, &CR50);           /* Falling edge of HREF ends  */  
      set_bit(1, &CR50);           /* capture line. */
      
      /* Enable Capture CR51[3] = 1 */
      set_bit(3, &CR51); 
      
      /* Enable Video Window CR3E[0] = 1 */
      set_bit(0, &CR3E);

      gd_write_cr(card_p, CR5C, 0x5c);
      gd_write_cr(card_p, CR58, 0x58);
      gd_write_cr(card_p, CR51, 0x51);
      gd_write_cr(card_p, CR50, 0x50);
      gd_write_cr(card_p, CR3E, 0x3e);

}

void gd_disable_window(struct clgd54xx_card * card_p)
{
      unsigned long CR3E, CR50, CR51;
       
      CR3E = gd_read_cr(card_p, 0x3e);
      CR50 = gd_read_cr(card_p, 0x50);
      CR51 = gd_read_cr(card_p, 0x51);


      /*    Disable Capture CR51[3] = 0 */
      clear_bit(3, &CR51);  

      /*    Reset Capture input to standard feature 
            connector CR50[1:0] = 11  */

      clear_bit(0, &CR50);           /* Falling edge of HREF ends capture */
      clear_bit(1, &CR50);  

      /* Disable Video Window CR3E[0] = 0 */
      clear_bit(0, &CR3E);


      gd_write_cr(card_p, CR51, 0x51);
      gd_write_cr(card_p, CR50, 0x50);
      gd_write_cr(card_p, CR3E, 0x3e);
}

void gd_set_vbuf1(struct clgd54xx_card * card_p, unsigned long ptr)
{
        unsigned long CR3A, CR3B, CR3C, CR5D;


      CR3A = gd_read_cr(card_p, 0x3a);
      CR3B = gd_read_cr(card_p, 0x3b);
      CR3C = gd_read_cr(card_p, 0x3c);
      CR5D = gd_read_cr(card_p, 0x5d);

      /* CR5D[3:2] = ptr[1:0]  */

      gd_bit_copy( &CR5D, 2, &ptr, 0, 1);

      /* CR3A = ptr[9:2] */

      gd_bit_copy( &CR3A, 0, &ptr, 2, 9);

      
      /* CR3B = ptr[17:10] */

      gd_bit_copy(&CR3B, 0, &ptr, 10, 17);

      /* CR3C[3:0] = ptr[21:18] */

      gd_bit_copy(&CR3C, 0, &ptr, 18, 21);

      gd_write_cr(card_p, CR3A, 0x3a);
      gd_write_cr(card_p, CR3B, 0x3b);
      gd_write_cr(card_p, CR3C, 0x3c);
      gd_write_cr(card_p, CR5D, 0x5d);

}

void gd_set_vbuf2(struct clgd54xx_card * card_p, unsigned long ptr)
{
        unsigned long CR59, CR5A, CR58, CR5D;

      CR59 = gd_read_cr(card_p, 0x59);
      CR5A = gd_read_cr(card_p, 0x5a);
      CR58 = gd_read_cr(card_p, 0x58);
      CR5D = gd_read_cr(card_p, 0x5d);

      /* CR5D[3:2] = ptr[1:0] */

      gd_bit_copy(&CR5D, 2, &ptr, 0, 1);

      /* CR59 = ptr[9:2]  */

      gd_bit_copy(&CR59, 0, &ptr, 2, 9);
      
      /* CR5A = ptr[17:10] */

      gd_bit_copy(&CR5A, 0, &ptr, 10, 17);

      /* CR58[3:0] = ptr[21:18] */

      gd_bit_copy(&CR58, 0, &ptr, 18, 21);

      gd_write_cr(card_p, CR59, 0x59);
      gd_write_cr(card_p, CR5A, 0x5a);
      gd_write_cr(card_p, CR58, 0x58);
      gd_write_cr(card_p, CR5D, 0x5d);

}

unsigned long gd_get_vbuf1(struct clgd54xx_card * card_p)
{
        unsigned long CR3A, CR3B, CR3C, CR5D;
      unsigned long ptr;

      CR3A = gd_read_cr(card_p, 0x3a);
      CR3B = gd_read_cr(card_p, 0x3b);
      CR3C = gd_read_cr(card_p, 0x3c);
      CR5D = gd_read_cr(card_p, 0x5d);

      /*  ptr[1:0]  = CR5D[3:2] */
      ptr = 0;
      gd_bit_copy( &ptr, 0, &CR5D, 2, 3);

      /*  ptr[9:2] = CR3A */

      gd_bit_copy( &ptr, 2, &CR3A, 0, 7);

      
      /* ptr[17:10] = CR3B */

      gd_bit_copy(&ptr, 10, &CR3B, 0, 7);

      /* ptr[21:18] = CR3C[3:0] */

      gd_bit_copy(&ptr, 18, &CR3C, 0, 3);

      return ptr;

}


unsigned long gd_get_vbuf2(struct clgd54xx_card * card_p)
{
        unsigned long CR59, CR5A, CR58, CR5D;
      unsigned long ptr;

      CR59 = gd_read_cr(card_p, 0x59);
      CR5A = gd_read_cr(card_p, 0x5a);
      CR58 = gd_read_cr(card_p, 0x58);
      CR5D = gd_read_cr(card_p, 0x5d);

      /* ptr[1:0] = CR5D[3:2] */
      ptr = 0;
      gd_bit_copy(&ptr, 0, &CR5D, 2, 3);

      /* ptr[9:2] = CR59 */

      gd_bit_copy(&ptr, 2, &CR59, 0, 7);

      /* ptr[17:10] = CR5A */

      gd_bit_copy(&ptr, 10, &CR5A, 0, 7);

      /* ptr[21:18] = CR58[3:0] */
      
      gd_bit_copy(&ptr, 18, &CR58, 0, 3);
      return ptr;

}

void gd_set_pitch(struct clgd54xx_card * card_p, unsigned long offset)
{
      unsigned long CR3C, CR3D;
      
      CR3C = gd_read_cr(card_p, 0x3c);
      CR3D = gd_read_cr(card_p, 0x3d);

      /* CR3C[5] = offset[11], CR3D = offset[10:3] */

      gd_bit_copy(&CR3C, 5, &offset ,11, 11);

      gd_bit_copy(&CR3D, 0, &offset, 3, 10);

      gd_write_cr(card_p, CR3C, 0x3c);
      gd_write_cr(card_p, CR3D, 0x3d);

}


unsigned long gd_get_pitch(struct clgd54xx_card * card_p)
{

      unsigned long CR3C, CR3D;
      unsigned long offset ;


        CR3C = gd_read_cr(card_p, 0x3c);
        CR3D = gd_read_cr(card_p, 0x3d);
      
      /* offset[11] = CR3C[5] , offset[10:3] = CR3D */
      offset = 0;
      gd_bit_copy(&offset, 11, &CR3C, 5, 5);
      gd_bit_copy(&offset, 3, &CR3D, 0, 7);

      return offset;
}



void gd_init_video( struct clgd54xx_card * card_p )
{
      unsigned long temp_reg;
      unsigned long  CR31, CR32, CR3E, CR3F, CR50, CR51, CR56, 
            CR57, CR58, CR5C, CR5E;

/*    unsigned long GRC, GRD; */
 
      CR31 = gd_read_cr(card_p, 0x31);
      CR32 = gd_read_cr(card_p, 0x32);
      CR3E = gd_read_cr(card_p, 0x3e);
      CR3F = gd_read_cr(card_p, 0x3f);
      CR50 = gd_read_cr(card_p, 0x50);
      CR51 = gd_read_cr(card_p, 0x51);
      CR56 = gd_read_cr(card_p, 0x56);
      CR57 = gd_read_cr(card_p, 0x57);
      CR58 = gd_read_cr(card_p, 0x58); /* Dependancy only on maxheight */
      CR5C = gd_read_cr(card_p, 0x5c);
      CR5E = gd_read_cr(card_p, 0x5e);


      /*    GRC = gd_read_gr(card_p, 0x0c); */
      /*    GRD = gd_read_gr(card_p, 0x0d); */

      /* Set the maximum scanlines to 512, we don't want 
       *  wanton clipping. */

      temp_reg = 0xff;
      gd_bit_copy(&CR57, 0, &temp_reg, 0, 7);
      set_bit(5, &CR58);

      /* Luminance only capture disabled */
      /* CR5C[5] = 0 */
      
      clear_bit(5, &CR5C);

      /* Count lines upto capture, set to zero */
      /* CR56[4:0] = 0 */

      temp_reg = 0;
      gd_bit_copy(&CR56, 0, &temp_reg, 0, 4);

      /* Non - Interlaced capture */
      /* CR50[6] = 0 */

      clear_bit(6, &CR50);

      /* 8bits, VPort width */
      /* CR50[4] = 0; */

      clear_bit(4, &CR50);

      /* Double clock capture */
      /* CR50[3] = 1; */
      
      set_bit(3, &CR50);
        

      /* Video Capture (Not Teletext) */
      /* CR5C[7] = 0 */

      clear_bit(7, &CR5C);

      /* Capture Data Format - YUV 4:2:2 */
      /* CR51[2:0] = 000 */

      clear_bit(0, &CR51);
      clear_bit(1, &CR51);
      clear_bit(2, &CR51);

      /* Display Data Format - YUV 4:2:2 */
      /* CR3E[3:1] = 000 */
      /* CR3F[4] = 0 */

      clear_bit(1, &CR3E);
      clear_bit(2, &CR3E);
      clear_bit(3, &CR3E);
      clear_bit(4, &CR3F);

      /* Double Buffer Control - Autoswitch */
      /* CR5E[5:4] = 10 */

      clear_bit(4, &CR5E);
      set_bit(5, &CR5E);


      /* Set Zoom = 1:1 ie., ZoomX = ZoomY = 0 */
      /* ZoomX = CR31, ZoomY = CR32 */
      CR31 = CR32 = 0;
      
      /* Also, Zoom mode set to 1; ie; line replication, 
       * in anticipation of chromakeying..
       */
      set_bit(4, &CR3E);

      /* Occlusion set to Colour Key, tagged compare (16 bit). */
      /* CR1D[5:3] = 011 */

      /*    set_bit(3, &CR1D); */
      /*    clear_bit(4, &CR1D); */
      /*    clear_bit(5, &CR1D); */
       


      /* Set the Chroma key. */

      /*    GRC = 0; */
      /*    GRD = GD_CHROMA_KEY; */
       
      /* Switch on Chromakeying */
      /*    set_bit(7, &CR3E); */

      /*    gd_write_gr(card_p, GRC, 0x0c); */
      /*    gd_write_gr(card_p, GRD, 0x0d); */

      gd_write_cr(card_p, CR50, 0x50);
      gd_write_cr(card_p, CR51, 0x51);
      gd_write_cr(card_p, CR56, 0x56);
      gd_write_cr(card_p, CR57, 0x57);
      gd_write_cr(card_p, CR58, 0x58); /* May be safely removed with Mx ht.*/
      gd_write_cr(card_p, CR5C, 0x5c);
      gd_write_cr(card_p, CR5E, 0x5e);
      gd_write_cr(card_p, CR31, 0x31);
      gd_write_cr(card_p, CR32, 0x32);
      gd_write_cr(card_p, CR3E, 0x3e);
      gd_write_cr(card_p, CR3F, 0x3f);
}

void gd_get_window(struct clgd54xx_card * card_p,
               struct video_window *winstruct,
               struct video_buffer * vbuf)
{
      int depth;
      unsigned long R1SZ, R1Adjust, R2SZ, R2Adjust, R2DSZ, WVS, WVE, WAO;
      unsigned long CR33, CR34, CR35, CR36, CR37, CR38, CR39, CR5D;

      depth = (vbuf->depth == 32 ? 24 : vbuf->depth);
        CR33 = gd_read_cr(card_p, 0x33);
      CR34 = gd_read_cr(card_p, 0x34);
      CR35 = gd_read_cr(card_p, 0x35);
      CR36 = gd_read_cr(card_p, 0x36);
      CR37 = gd_read_cr(card_p, 0x37);
      CR38 = gd_read_cr(card_p, 0x38);
      CR39 = gd_read_cr(card_p, 0x39);
      CR5D = gd_read_cr(card_p, 0x5d);


      /* R1SZ = CR36[1:0] CR33 */
      R1SZ = 0;
      gd_bit_copy(&R1SZ, 8, &CR36, 0, 1);
      gd_bit_copy(&R1SZ, 0, &CR33, 0, 7);
      
      /* R1Adjust = CR5D[1:0] */

      R1Adjust = 0;
      gd_bit_copy(&R1Adjust, 0, &CR5D, 0, 1);

      /* R2SZ = CR36[3:2] CR34 */
      R2SZ = 0;
      gd_bit_copy(&R2SZ, 8, &CR36, 2, 3);
      gd_bit_copy(&R2SZ, 0, &CR34, 0, 7);

      /* R2Adjust = CR5D[5:4] */
      R2Adjust = 0;
      gd_bit_copy(&R2Adjust, 0, &CR5D, 4, 5);

      /* R2DSZ = CR36[5:4] CR35 */
      R2DSZ = 0;
      gd_bit_copy(&R2DSZ, 8, &CR36, 4, 5);
      gd_bit_copy(&R2DSZ, 0, &CR35, 0, 7);

      /* WVS = CR39[1:0] CR37 */
      WVS = 0;
      gd_bit_copy(&WVS, 8, &CR39, 0, 1);
      gd_bit_copy(&WVS, 0, &CR37, 0, 7);

      /* WVE = CR39[3:2] CR38 */
      WVE = 0;
      gd_bit_copy(&WVE, 8, &CR39, 2, 3);
      gd_bit_copy(&WVE, 0, &CR38, 0, 7);

      WAO = 0;

      WAO = gd_get_pitch(card_p);


      tprintk("gd_get_window() hardware registers read:\n
                depth = %d bpp \n
                R1SZ = %ld\n
                R1Adjust = %ld\n
                R2SZ = %ld\n 
                R2Adjust = %ld\n 
                R2DSZ = %ld\n 
                WVS=%ld\n WVE=%ld\n 
                WAO=%ld\n", depth,
            R1SZ, R1Adjust, R2SZ, R2Adjust, R2DSZ, WVS, WVE, WAO);

      winstruct->x = R1SZ * 32 / depth + R1Adjust * 8 / depth;

      winstruct->width = R2SZ * 32 / depth + R2Adjust * 8 / depth;

      winstruct->y = WVS;
      winstruct->height = WVE - WVS;

}


void gd_set_window(struct clgd54xx_card * card_p,
               struct video_window *winasked,
               struct video_window *wingiven,
               struct video_buffer *vbuf)
{
      int depth;
      unsigned long R1SZ, R1Adjust, R2SZ, R2Adjust, R2DSZ, WVS, WVE, WAO;
      unsigned ZOOMY, CR32;
      unsigned long CR33, CR34, CR35, CR36, CR37, CR38, CR39, CR5D;

      depth = (vbuf->depth == 32 ? 24 : vbuf->depth);

      /* Safety Checks and clipping, for window borders. */

      winasked->x = winasked->x < 0 ?
            0 : winasked->x;

      winasked->y = winasked->y < 0 ?
            0 : winasked->y;
            
      winasked->width = (vbuf->width - winasked->x) < winasked->width ?
            (vbuf->width - winasked->x) : winasked->width;

      winasked->height = (vbuf->height - winasked->y) < winasked->height ?
            (vbuf->height - winasked->y) : winasked->height;


      R1SZ = (winasked->x * depth) / 32;
      R1Adjust = (winasked->x * depth - R1SZ * 32) / 8;
      
      R2SZ = (winasked->width * depth) / 32;
      R2Adjust = (winasked->width * depth - R2SZ * 32) / 8;

      /*ugly hack. only tried on 24bpp and 16bpp eqn is. vbpp/gbpp * .5 */

      R2DSZ = R2SZ * 16 / depth + R2Adjust * 4 / depth;

      WVS = winasked->y;

      WVE = WVS + winasked->height;

      WAO = R2SZ * 4; 

      /* Zoom treatment. Doing zoom just for Vlines.
       * Notes: Occlusion, ie; chromakeying and line interpolation 
       * (in the case of zooming) are mutually exclusive. 
       */
      
      if(wingiven->height < winasked->height)
            {
                  ZOOMY = (wingiven->height * 256) / winasked->height - 5;
                  CR32 = ZOOMY;
            }
      else
            CR32 = 0;      /* Don't want old Zoom values lying about. */
                  
                  

      /* CR36[1:0] CR33 = R1SZ */
      gd_bit_copy(&CR36, 0, &R1SZ, 8, 9);
      gd_bit_copy(&CR33, 0, &R1SZ, 0, 7);
      
      /* CR5D[1:0] = R1Adjust */
      gd_bit_copy(&CR5D, 0, &R1Adjust, 0, 1);

      /* CR36[3:2] CR34 = R2SZ */
      gd_bit_copy(&CR36, 2, &R2SZ, 8, 9);
      gd_bit_copy(&CR34, 0, &R2SZ, 0, 7);

      /* CR5D[5:4] = R2Adjust */
      
      gd_bit_copy(&CR5D, 4, &R2Adjust, 0, 1);

      /* CR36[5:4] CR35 = R2DSZ */
      
      gd_bit_copy(&CR36, 4, &R2DSZ, 8, 9);
      gd_bit_copy(&CR35, 0, &R2DSZ, 0, 7);

      /* CR39[1:0] CR37 = WVS */
      
      gd_bit_copy(&CR39, 0, &WVS, 8, 9);
      gd_bit_copy(&CR37, 0, &WVS, 0, 7);

      /* CR39[3:2] CR38 = WVE */
      
      gd_bit_copy(&CR39, 2, &WVE, 8, 9);
      gd_bit_copy(&CR38, 0, &WVE, 0, 7);

      /* CR36[5:4] CR35 = R2DSZ */

      gd_bit_copy(&CR36, 4, &R2DSZ, 8, 9);
      gd_bit_copy(&CR35, 0, &R2DSZ, 0, 7);

      gd_set_pitch(card_p, WAO);

      tprintk("gd_set_window() hardware registers set to:\n
                R1SZ = %ld\n
                R1Adjust = %ld\n
                R2SZ = %ld\n 
                R2Adjust = %ld\n 
                R2DSZ = %ld\n 
                WVS=%ld\n WVE=%ld\n 
                WAO=%ld\n", 
            R1SZ, R1Adjust, R2SZ, R2Adjust, R2DSZ, WVS, WVE, WAO);

            gd_write_cr(card_p, CR5D, 0x5d);  
            gd_write_cr(card_p, CR39, 0x39);  
            gd_write_cr(card_p, CR38, 0x38);  
            gd_write_cr(card_p, CR37, 0x37);  
            gd_write_cr(card_p, CR36, 0x36);  
            gd_write_cr(card_p, CR35, 0x35);  
            gd_write_cr(card_p, CR34, 0x34);  
            gd_write_cr(card_p, CR33, 0x33);  
            gd_write_cr(card_p, CR32, 0x32);  
}

/* returns clipped windows, according to available ram, with
 * video buffer starting as close to the end of video ram as possible.
 */

long gd_window_init(struct clgd54xx_card * card_p)
{

      int scrn_depth;
      unsigned long vbuf1_ptr, vbuf2_ptr, scrn_ht, scrn_wt, vram;

      vram = card_p->vram = gd_count_ram(card_p);

      scrn_ht = card_p->drv_stat_p->vbuf_p->height;
      scrn_wt = card_p->drv_stat_p->vbuf_p->width;
      scrn_depth = card_p->drv_stat_p->vbuf_p->depth;
      scrn_depth = scrn_depth == 32 ? 24 :scrn_depth;

      vbuf1_ptr = vram * 1048576 - 16384 - scrn_ht * scrn_wt * 2;

      /* Eeeks!!! No check for video data spilling over into framebuffer
       * space. OK folk. Get ready for full screen video! 

      if(vbuf1_ptr < (scrn_ht * scrn_wt * scrn_depth / 8)) return -1;
      
      */

      vbuf2_ptr = vbuf1_ptr;

      gd_init_video(card_p);

      printk("Marker \n");

      gd_set_vbuf1(card_p, vbuf1_ptr);
      gd_set_vbuf2(card_p, vbuf2_ptr);

      return vbuf2_ptr;

}

/* V4L Driver Callback functions */

static int pvcl_open(struct inode *inode, struct file *file)
{

      unsigned int minor = minor(inode->i_rdev);
      struct clgd54xx_card * card_p;


      file->private_data = &clgd54xx_card_info;
      card_p = file->private_data;

      do_client_ioctl(file, VPROC_INIT, &card_p->model);

      dprintk("pvcl_open called on minor %d\n", minor);

      return 0;
}

static int pvcl_release(struct inode *inode, struct file *file)
{
      file->private_data = NULL;
      
      dprintk("pvcl_release called.\n");
      return 0;
}

static int pvcl_do_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, void *arg)
{

      struct clgd54xx_card * card_p = file->private_data;

      switch(cmd) {
            
      case VIDIOCGCAP:
            {
                  struct video_capability *cap = arg; 
                  struct video_buffer *bufstat = 
                        card_p->drv_stat_p->vbuf_p;

                  sprintf(cap->name, "pvcl");
                  
                  cap->type = VID_TYPE_TUNER | VID_TYPE_OVERLAY | 
                        VID_TYPE_FRAMERAM  | VID_TYPE_SCALES;
                  
                  cap->channels = 1; /* Just one channel for now. */
                  cap->audios = 1;

                  /* Max Screen Size reported by X11 via v4l-conf */
                  cap->maxwidth = bufstat->width;    
                  cap->maxheight = bufstat->height;  
                  cap->minwidth = 32;  /* Hardcoded vpx 3225D specific */
                  cap->minheight = 24;
                  
                  /* Hard Code PAL for the moment. */

                  do_client_ioctl(file, VPROC_SET_CAP_MODE,
                              &card_p->drv_stat_p->vtun_p->mode);

                  dprintk("VIDIOCGCAP called\n");
            
                  return 0;
            }

      case VIDIOCGFBUF:
            {
                  struct video_buffer *buf = arg;
                  struct video_buffer *bufstat = 
                        card_p->drv_stat_p->vbuf_p;

                  memcpy(buf, bufstat, sizeof(*buf));

                  dprintk("VIDIOCGFBUF called. \n");

                  return 0;

            }
            
      case VIDIOCSFBUF:
            {
                  
                  struct video_buffer *buf = arg;
                  struct video_buffer *bufstat = 
                        card_p->drv_stat_p->vbuf_p;


                  /* HEEEEEEEEEEEEELOOOOOOOOOOOOOOOO, Careful. Security 
                     hole here!!!!!!!!!!! 
                  */
                  /* Security check disabled for now.
                     if(!capable(CAP_SYS_ADMIN) &&
                     !capable(CAP_SYS_RAWIO))
                     return -EPERM;
                  */

                  memcpy(bufstat, buf, sizeof(*bufstat));
                  
                  dprintk("VIDIOCSFBUF called. \n");
                  printk(KERN_INFO "client reports:\n
                              screen size: %dx%d @ %dbpp. 
                              %d bytesperline.\n.", 
                         bufstat->width, 
                         bufstat->height, 
                         bufstat->depth, 
                         bufstat->bytesperline);

                  dprintk("Capture Buffer set to 0x%p", bufstat->base);

                  /* Now that we've got the Screen Parms, 
                   * we can inititialize the window */

                  gd_window_init(card_p); 

                  return 0;
            }
            
            
      case VIDIOCCAPTURE:
            {
                  int *on = arg;
                  struct video_buffer *bufstat = 
                        card_p->drv_stat_p->vbuf_p;
                  
                  if (*on) {
                        /* verify args */
                        if (NULL == bufstat->base)
                              return -EINVAL;
                        if (bufstat->width <32 ||
                            bufstat->height <24 ||
                            bufstat->width >800 ||
                            bufstat->height >600)
                            
                            return -EINVAL;
                  }

                  if(*on) {
                        

                        /* Tell vpx to switch on. `on' is dummy here.*/

                        do_client_ioctl(file, VPROC_START_CAPTURE, on);
                        gd_enable_window(card_p); 
                        
                        dprintk("VIDIOCCAPTURE: video window switched on. \n");
                        return 0;
                  }

                  else {

                        /* Tell vpx to stop capture. `on'  is dummy.*/

                        do_client_ioctl(file, VPROC_STOP_CAPTURE, on);

                        gd_disable_window(card_p); 

                        dprintk("VIDIOCCAPTURE: video window switched off. \n");
                        return 0;
                  }
                        
            }
            
      case VIDIOCGWIN:
            {
                  struct video_window *winarg = arg;
                  struct video_window *winstat = 
                        card_p->drv_stat_p->vwin_p;
                  
                  memcpy(winarg, winstat, sizeof(*winarg));

                  /* TODO: Need to get actual window parms from
                   * hardware. Use gd_get_video_window()
                   */

                  dprintk("VIDIOCGWIN called. \n");
                  return 0;
            }


      case VIDIOCSWIN:
            {
                  struct video_window *winarg = arg;
                        struct video_window *winstat = 
                        card_p->drv_stat_p->vwin_p;
                  struct video_buffer *bufstat = 
                        card_p->drv_stat_p->vbuf_p;

                  memcpy(winstat, winarg, sizeof(*winstat));


                  tprintk("VIDIOCSWIN recieved:\n 
                                \t position:   %d, %d \n 
                                \t dimensions: %d, %d \n",
                                winstat->x,
                        winstat->y, 
                        winstat->width, 
                        winstat->height); 

                  do_client_ioctl(file, VPROC_SET_WINDOW, winarg); 

                  /* gd_set_window(card_p, app_wants, vproc_gives....) */

                  gd_set_window(card_p, winstat, winarg, bufstat); 

                  tprintk("gd_set_window() recieved:\n 
                                \t position:   %d, %d \n 
                                \t dimensions: %d, %d \n",
                                winstat->x,
                        winstat->y, 
                        winstat->width, 
                        winstat->height); 

                  gd_get_window(card_p, winstat, bufstat);   

                  tprintk("gd_get_window returned: \n 
                                \t position:   %d, %d \n 
                                \t dimensions: %d, %d \n",
                                winstat->x,
                        winstat->y, 
                        winstat->width, 
                        winstat->height); 


                        dprintk("VIDIOCSWIN called. \n");
                        return 0;
                }

            /* Wrappers for tuner.c - hacked from bttv-driver.c 
               which is copyrighted to :
             
               Copyright (C) 1996,97,98 
               Ralph  Metzler <rjkm@thp.uni-koeln.de>,
               Marcus Metzler <mocm@thp.uni-koeln.de>,
               &
               (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
 
            */
            
        case VIDIOCGTUNER:
            {
                  struct video_tuner *v = arg;
                  struct video_tuner *vstat = 
                        card_p->drv_stat_p->vtun_p;

                  if (v->tuner) /* Only tuner 0 */
                        return -EINVAL;

                  do_client_ioctl(file,cmd,v);

                  /* tuner.c returns v->signal, ie; signal strength. */
                  memcpy(v, vstat, sizeof(*v));

                  dprintk("VIDIOCGTUNER has been called. \n");
                  return 0;

            }                             
            
        case VIDIOCSTUNER:
            {
                  struct video_tuner *v = arg;
                  struct video_tuner *vstat = 
                        card_p->drv_stat_p->vtun_p;

                  if (v->tuner) /* Only tuner 0 */
                        return -EINVAL;
                  if (v->mode > VIDEO_MODE_PAL)
                        return -EINVAL;
                  
                  do_client_ioctl(file,cmd,v);

                  vstat->mode = v->mode;

                  dprintk("VIDIOCSTUNER has been called. \n");

                  return 0;
            }

        case VIDIOCGFREQ:
            {
                  unsigned long *freq = arg;
                  *freq = card_p->drv_stat_p->freq;
                  dprintk("VIDIOCGFREQ called.\n");
            
                  return 0;
            }
        case VIDIOCSFREQ:
            {
                  unsigned long *freq = arg;

                  do_client_ioctl(file,cmd,freq);
                  
                  card_p->drv_stat_p->freq=*freq;
                  dprintk("VIDIOCSFREQ called.\n");

                  return 0;
            }

        case VIDIOCSCHAN:
            {
                  struct video_channel *v = arg;
                  struct video_tuner *vstat = card_p->drv_stat_p->vtun_p;

                  if (v->channel >  0)
                        return -EINVAL;

                  if(v->norm > VIDEO_MODE_PAL)
                        return -EINVAL;

                  /* TODO: need to implement tv norms. 
                   * Currently hardcoded
                   * to PAL. See struct video_channel 
                   * vchan_s decl above. */

                  do_client_ioctl(file,cmd,v);

                  memcpy(vstat, v , sizeof(*v));
                  dprintk("VIDIOCSCHAN has been called. \n");
                  return 0;
            }
            
        case VIDIOCGCHAN:
            {
                  struct video_channel *v = arg;
                  struct video_channel *chanstat = 
                        card_p->drv_stat_p->vchan_p;

                  memcpy(v, chanstat, sizeof(*v));

                  dprintk("VIDIOCGCHAN has been called. \n");

                  return 0;
            }

            /* End bttv-driver.c wrappers. */


      case VIDIOCGPICT:
            {
                  struct video_picture *vpict = arg;
                  struct video_picture *vpictstat =
                        card_p->drv_stat_p->vpict_p;

                  memcpy(vpict, vpictstat, sizeof(*vpict));

                  dprintk("VIDIOCGPICT has been called. \n");
            }


      case VIDIOCSPICT:
            {
                  struct video_picture *vpict = arg;
                  struct video_picture *vpictstat =
                        card_p->drv_stat_p->vpict_p;

                  memcpy(vpictstat, vpict, sizeof(*vpict));

                  do_client_ioctl(file, VPROC_SET_PICTURE, vpictstat);
                  
                  dprintk("VIDIOCGPICT has been called. \n");
            }
      }     
      
      return -ENOIOCTLCMD;
      

      
}


static int pvcl_ioctl(struct inode *inode, struct file *file,
                  unsigned int cmd, unsigned long arg)
{
      return video_usercopy(inode, file, cmd, arg, pvcl_do_ioctl);
}

static ssize_t pvcl_read(struct file *file, char *data,
                     size_t count, loff_t *ppos)
{
      return 0;
}

static struct file_operations pvcl_fops =
{
      owner:      THIS_MODULE,
      open:       pvcl_open,
      release:    pvcl_release,
      ioctl:      pvcl_ioctl,
      llseek:     no_llseek,
      read:       pvcl_read
};

static struct video_device pvcl_video_dev =
{
      name:      "PVCL ver 0.1",
      type:       VID_TYPE_TUNER | VID_TYPE_OVERLAY |
                    VID_TYPE_FRAMERAM | VID_TYPE_SCALES,
      fops:       &pvcl_fops,
      minor:      -1
};


/* Device Registration */
static int __devinit pvcl_register_video(struct video_device * video_dev )
{
      if(video_register_device(video_dev, VFL_TYPE_GRABBER, 0)<0)
            return -1;
      printk(KERN_INFO "pvcl: registered device video\n");

      return 0;


}

static void __devexit pvcl_unregister_video(struct video_device * video_dev)
{
      video_unregister_device(video_dev);
}

static int pvcl_init_module(void)
{
      int retval;

      if( (retval = pvcl_register_video( &pvcl_video_dev)) ) return retval;
      if( (retval = i2c_clgd54xx_init(&clgd54xx_card_info, 
                              &clgd54xx_adap,
                              &clgd54xx_bitbang_adap)) )
            return retval;

      switch(debug)
            {
            case 1:
                  {
                        printk(KERN_INFO "pvcl: Functional Debug messages enabled.\n");
                        break;
                  }
            case 2:
                  {
                        printk(KERN_INFO "pvcl: Debug messages enabled per function.\n");
                        break;
                  }
            case 3:
                  printk(KERN_INFO "pvcl: WARNING: Verbose Debugging enabled - kernel printk buffers may overflow.\n");
                  break;
            }


      return retval;

}

static void pvcl_cleanup_module(void)
{
      i2c_clgd54xx_cleanup(&clgd54xx_card_info);
      pvcl_unregister_video(&pvcl_video_dev);
}

module_init(pvcl_init_module);
module_exit(pvcl_cleanup_module);

MODULE_PARM(debug,"i");
MODULE_PARM_DESC(debug,"debug messages, default 0, is don't debug.");

MODULE_DESCRIPTION("pvcl - v4l driver module for the pixelview combo tv plus");
MODULE_AUTHOR("Cherry George Mathew");
MODULE_LICENSE("GPL");

/*
 * Local variables:
 * c-basic-offset: 8
 * End:
 */

Generated by  Doxygen 1.6.0   Back to index