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;
}