Subversion Repositories shark

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed


/*
 Nome File : pxc.c
 Autore : Danilo Dealberti
          Claudio Melita
 Data : 16-11-1999
 Descrizione : modulo di implementazione delle funzioni del PXC200
 Modifiche :
*/

/*
 Note :
 Il seguente modulo permette Š in grado di supportare ogni frame grabber
 dotato del controllore single-chip Bt848/Bt848A/Bt849 della BrookTree (ora
 Conexant)
 Per variare la risoluzione di acquisizione o il formato dei dati in ingresso
 vanno variati i parametri contenuti nel seguente modulo , il quale Š
 specifico per immagini di 384x288 pixel codificate a 8 livelli di grigio
 Le modifiche possono essere effettuate consultando il manuale di descrizione del
 chip Bt848 disponibile al sito www.Conexant.com
*/


#include <kernel/func.h>
#include <sys/types.h>
#include <drivers/pci.h>
#include <drivers/pxc.h>
#include <drivers/llpci.h>
#include "../../drivers/pci/linuxpci.h"

#define appl2linear(x) (x)

// Prototipi locali
void PXC_fast(void);
void Generate_Program(DWORD *B1);
void Modify_Program(DWORD *B1);

// Variabili locali al modulo
static DWORD BaseAddr;
static BYTE IntLine;
static unsigned char *Corpo;
static unsigned char V_Corpo[7000];
static DWORD *Pun;
static DWORD Programma;
static DWORD Buffer1;
static int errore;
static PXC_Listeners Lista;
static BYTE bus,dev;
static TIME per;
static TIME Fotogramma;
static DWORD old;
static CAB Depositi;
static unsigned char *pointer;


TIME PXC_Initiate(int number) {
   struct pci_regs *reg;                  
   unsigned register int i;
   BYTE dep;
   DWORD dw;
//   MODEL m=BASE_MODEL;
//   TIME wcet;


   reg=NULL;
   if (pci_init()==1) {
      reg = (struct pci_regs *) pci_class((0x0400) << 8,0,&bus,&dev) ;
      if (reg != NULL) {
         // Ottiene l' indirizzo di base del frame grabber
         BaseAddr = (reg->IoBaseAddress-0x08); ;
         IntLine = reg->InterruptLine; // Ottiene la linea di interrupt
      } else {
         errore = 1;
         return 0;
      }
   } else {
      errore =2;
      return 0;
   }

   pcibios_read_config_dword(bus,dev,PCI_COMMAND,&dw);
   old=dw;
   dw |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER) ; // Abilita il mastering del BUS PCI e anche la mappatura in memoria
   pcibios_write_config_dword(bus,dev,PCI_COMMAND,dw);

   // Controllo della presenza di video input
   dep = (BYTE) lmempeekb((void *)(BaseAddr+PXC_DSTATUS));

   if (dep & 0x80) {

     // Creazione del CAB in base al numero di processi interessati
     Depositi = cab_create("",PXC_MAXX*PXC_MAXY*sizeof(unsigned char),number+2);
     if (Depositi<0) return 0;
   
      // Autoformat detected enabled
      lmempokeb((void *)(BaseAddr+PXC_IOFORM),0x58);
     
      // Fattore di scala orizzontale 2:1
      lmempokeb((void *)(BaseAddr+ PXC_E_HSCALE_HI),0x16);
      lmempokeb((void *)(BaseAddr+ PXC_E_HSCALE_LO),0x79);
      lmempokeb((void *)(BaseAddr+ PXC_O_HSCALE_HI),0x16);
      lmempokeb((void *)(BaseAddr+ PXC_O_HSCALE_LO),0x79);

      // Fattore di scala verticale 1:1
      lmempokeb((void *)(BaseAddr+ PXC_E_VSCALE_HI),0x60);
      lmempokeb((void *)(BaseAddr+ PXC_E_VSCALE_LO),0);
      lmempokeb((void *)(BaseAddr+ PXC_O_VSCALE_HI),0x60);
      lmempokeb((void *)(BaseAddr+ PXC_O_VSCALE_LO),0);

      // Numero di pixel orizzontali formanti l'immagine
      lmempokeb((void *)(BaseAddr+ PXC_E_HACTIVE_LO),0x80);
      lmempokeb((void *)(BaseAddr+ PXC_O_HACTIVE_LO),0x80);

      // Numero di pixel verticali formanti l'immagine
      lmempokeb((void *)(BaseAddr+ PXC_E_VACTIVE_LO),0x40);
      lmempokeb((void *)(BaseAddr+ PXC_O_VACTIVE_LO),0x40);

      // Temporizzazione verticale
      lmempokeb((void *)(BaseAddr+ PXC_E_VDELAY_LO),0x20);
      lmempokeb((void *)(BaseAddr+ PXC_O_VDELAY_LO),0x20);

      // Tempozizzazione Orizzontale
      lmempokeb((void *)(BaseAddr+ PXC_E_HDELAY_LO),0x4d);
      lmempokeb((void *)(BaseAddr+ PXC_O_HDELAY_LO),0x4d);

      // Parte alta di VACTIVE HACTIVE VDELAY HDELAY
      lmempokeb((void *)(BaseAddr+ PXC_E_CROP), 0x21);
      lmempokeb((void *)(BaseAddr+ PXC_O_CROP),0x21);

      // Temporizzazione del convertitore ADC e del periodo di burst
      lmempokeb((void *)(BaseAddr+ PXC_ADELAY),0x7f);
      lmempokeb((void *)(BaseAddr+ PXC_BDELAY),0x72);

      // Setta l'acquisizione a 8 livelli di grigio
      lmempokeb((void *)(BaseAddr+ PXC_COLOR_FMT), 0x66);

      // Generazione del programma nel buffer ottenuto dal CAB
      pointer = cab_reserve(Depositi);
      Generate_Program((DWORD *)pointer);
     
     // Cattura Full-Frame , sia even che odd field
     lmempokeb((void *)(BaseAddr+PXC_CAP_CTL),0x13);

     // Abilitazione delle interruzioni
     lmempoked((void *)(BaseAddr+PXC_INT_MASK),0x00001800);

     // Inserimento dell' indirizzo del programma RISC all' interno del
     // canale DMA
     lmempoked((void *)(BaseAddr+PXC_RISC_STRT_ADD),Programma);

     } else {
         errore=3;
         return 0;
     }

     // Inizializzazione della struttura dati utilizzata per
     // aggiungere processi ascoltatori dell' immagine

    for(i=0;i<PXC_MAX_LISTENERS;i++) {
         Lista.Elementi[i].proc=NIL;
         Lista.Elementi[i].DRel = 0;
    }
    Lista.Top=0;

    per = PXC_FRAME_TIME; // Ritorno periodo in us

    Fotogramma=0;

    return per;
}
/**************************************************************************/
void PXC_Start(void) {
   handler_set(IntLine, (void (*)(int))PXC_fast, NIL);
   lmempokew((void *)(BaseAddr+PXC_GPIO_DMA_CTL),0x0000);
   lmempokew((void *)(BaseAddr+PXC_GPIO_DMA_CTL),0x0003);
}

/**************************************************************************/

int PXC_Push_Listener(PID l, int drel)
{
   int pele;

   if (l == NIL) return 0;
   if (Lista.Top == PXC_MAX_LISTENERS) {
      errore=4;
      return 0; // Non vi sono pi— elementi liberi
   }

   
   pele = Lista.Top;
   Lista.Top++;

 // Setta tutto ci• che serve per il nuovo elemento
   Lista.Elementi[pele].proc=l;
   Lista.Elementi[pele].DRel = drel;

   return 1;
}
/**************************************************************************/

int PXC_Pop_Listener()
{
   if (Lista.Top > 0) {
      Lista.Top --;
      return 1;
   }
   return 0;
}
/**************************************************************************/
void PXC_Close(void)
{
//   DWORD dw;

 // Ferma il DMA
   lmempokew((void *)(BaseAddr+PXC_GPIO_DMA_CTL),0x0000);
   pcibios_write_config_dword(bus,dev,PCI_COMMAND,old);
   
   handler_remove(IntLine);
   for(;PXC_Pop_Listener();) ; // Li toglie tutti

   // Rimozione del CAB
   cab_delete(Depositi);

}
/*************************************************************************/
void PXC_fast(void) {
   DWORD pen;
   register int i;

   pen=lmempeekd((void *)(BaseAddr+PXC_INT_STAT));

   if (pen & 0x00000800) {

         // COMMIT al CAB
      cab_putmes(Depositi,pointer);

      // Interrompi il programma RISC
      lmempokew((void *)(BaseAddr+PXC_GPIO_DMA_CTL),0x0000);

      // Crea il nuovo programma in memoria dopo aver riservato il nuovo
      // CAB
      pointer=cab_reserve(Depositi);

      Modify_Program((DWORD *)pointer);

      // Riabilita il programma
      lmempokew((void *)(BaseAddr+PXC_GPIO_DMA_CTL),0x0003);

     
      Fotogramma++;

      // Attivazione dei task nel fast handler direttamente, visto il suo
      // tempo di esecuzione molto ridotto (decine di microsec contro un
      // interrupt period di 20 millisec )
      for(i=0;i<Lista.Top;i++)

         if (!(Fotogramma % Lista.Elementi[i].DRel)) {
           LEVEL l;
           PID p = Lista.Elementi[i].proc;

           if (proc_table[p].control & FREEZE_ACTIVATION)
             proc_table[p].frozen_activations++;
           else {
             l = proc_table[p].task_level;
             level_table[l]->task_activate(l,p);
             event_need_reschedule();
           }

//           task_activate(Lista.Elementi[i].proc);
         }

     
    } else {
  // C'Š un errore nell' acquisizione, per ora non lo trattiamo
    }
 
    lmempoked((void *)(BaseAddr+PXC_INT_STAT),pen); // EOI al Bt848

}

/*************************************************************************/
void Generate_Program(DWORD *B1)

{
 unsigned register int i;

      // Definizione del programma all' interno dello spazio di memoria puntato
      // da Programma , va DWORD aligned , quindi prima lo allineamo, poi
      // andiamo a scriverci dentro il programma, il quale pu• essere variabile
      // in funzione delle opzioni di ingresso
      Corpo = V_Corpo;
      Programma = appl2linear(Corpo);
      if (Programma % 4) {
         unsigned char diff;

        // Procediamo all' allineamento del buffer
         diff = (unsigned char)(((Programma / 4)+1) * 4 -Programma);
         Programma += diff;
         Corpo += diff;  // Anche il puntatore del buffer va aumentato
      }

      // Si innesca sempre da qui
      Pun = (DWORD *) Corpo;
     
      Buffer1 = appl2linear(B1);
      //Buffer2 = appl2linear(B2);
     
      (*Pun)=PXC_SYNC | PXC_FM1 ;
      Pun++;
      (*Pun)=0;
     
      for(i=0;i< PXC_MAXY;i++)
      {
         Pun++;
         (*Pun) = PXC_WRITE | PXC_SET_SOL | PXC_SET_EOL | PXC_MAXX ;
         Pun++;
         (*Pun)=(Buffer1+ i* PXC_MAXX);
      }
     
      Pun++;
      (*Pun) = PXC_SYNC | PXC_VRE | PXC_SET_IRQ ;
      Pun++;
      (*Pun) = 0;
     
      Pun++;
      (*Pun) = PXC_SYNC | PXC_FM1   ;
      Pun++;
      (*Pun) = 0;
      // Write mettendo SOL e EOL e come byte count 768 , come indirizzo
      // quello del buffer per il campo dispari
     
      for(i=0; i<PXC_MAXY; i++) {
         Pun++;
         (*Pun) = PXC_WRITE | PXC_SET_SOL | PXC_SET_EOL | PXC_MAXX ;
         Pun++;
         (*Pun)=(/*Buffer2*/Buffer1+i*PXC_MAXX);
      }
     
      Pun++;
      (*Pun) = PXC_SYNC | PXC_VRO ;
      Pun++;
      (*Pun)=0;
     
     
      // Jump all' indirizzo contenuto in programma e interrupt
      Pun++;
      (*Pun) = PXC_JUMP | PXC_SET_IRQ ;
      Pun++;
      (*Pun) = Programma;

     // Fine programma di istruzione del RISC DMA channels
}
/*********************************************************************/
void Modify_Program(DWORD *B1)

{
 unsigned register int i;

      // Si innesca sempre da qui
      Pun = (DWORD *) Corpo;
     
      Buffer1 = appl2linear(B1);

      Pun++;

      for(i=0;i< PXC_MAXY;i++)
      {
         Pun+=2;
         (*Pun)=(Buffer1+ i* PXC_MAXX);
      }
     
      Pun+=4;
      for(i=0; i<PXC_MAXY; i++) {
         Pun+=2;
         (*Pun)=(Buffer1+i*PXC_MAXX);
      }

     // Fine programma di istruzione del RISC DMA channels
}
/****************************************************************************/
CAB PXC_GetCab(void)
{
 return Depositi;
}