Forum Discussion
Altera_Forum
Honored Contributor
13 years agoHere an overview on my module
# include <linux/module.h> /* Allg. Modul Informationen */# include <linux/pci.h> /* PCI Funktionen */# include <linux/msi.h># include <linux/interrupt.h># include <asm/io.h>
# ifndef CONFIG_PCI# error "This driver needs PCI support to be available"# endif
/* Hersteller- und Geraetekennung */# define PCI_VENDOR_ID_LATTICE 0x1204# define PCI_DEVICE_ID_LATTICE_PCI 0xEC30
/* Name/Kennung fuer die PCI-Karte */# define LATTICE_PCI_NAME "LATTICE_pci"
/* Register Offsets */# define LATTICE_INTR_REG_ADDR 0x100
////////////////////////////////# define DMA_BUFFER_SIZE (64 * 1024)
size_t dmaBufSize; /**< size in bytes of the allocated kernel buffer */
dma_addr_t dmaPCIBusAddr; /**< PCI bus address to access the DMA buffer - program into board */
void *dmaCPUAddr; /**< CPU (software) address to access the DMA buffer - use in driver */
////////////////////////////////
////////////////////////////////# define msi_ID 0x01
//uint32_t msi_test;
//uint32_t msi_addr, msi_data;
uint32_t msi_ctrl, msi_data, msi_address_hi, msi_address_lo, msi_capability;
/* Alle geraetespezifischen Variablen werden in einer Struktur */
/* zusammengefasst. */
struct
{
/* Zeiger auf das Software-Objekt */
struct pci_dev *pci_dev;
/* Zeiger auf die virtuelle Basisadresse */
void *virt_addr;
/* Physikalische Adresse */
unsigned long phys_addr;
/* Adressraum (Umfang) */
unsigned long size;
/* Interrupt */
u8 intr_line;
} LATTICE_pci_dev;
/* Interrupt Handler */
irq_handler_t LATTICE_pci_intr_handler (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long intr_flag;
/* Lese Interrupt-Flag, um zu pruefen, ob das LATTICE PCI-Board ueberhaupt */
/* Quelle des Interrupts ist. (Moeglicherweise Shared Interrupt!) */
intr_flag = readl (LATTICE_pci_dev.virt_addr + LATTICE_INTR_REG_ADDR) & 1;
if (intr_flag) ; /* Kein Interrupt durch das LATTICE PCI-Board */
/* Hier beginnt die eigentliche Interrupt-Bearbeitung... */
{ printk ("LATTICE PCI-Board: Interrupt!\n");
return (irq_handler_t) IRQ_HANDLED;
}
return (irq_handler_t) IRQ_NONE;
}
/* Aufraeumen, wird bei 'rmmod' aufgerufen */
void cleanup_module(void)
{
/* Speicherbereich freigeben */
iounmap (LATTICE_pci_dev.virt_addr);
release_mem_region (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size);
free_irq (LATTICE_pci_dev.intr_line, &LATTICE_pci_dev);
pci_disable_msi(LATTICE_pci_dev.pci_dev);
}
/* Modul-Initialisierung, wird bei 'insmod' aufgerufen */
int init_module (void)
{
int result;
//u8 intr_pin;
LATTICE_pci_dev.pci_dev = NULL;
LATTICE_pci_dev.intr_line = 0;
/* Gibt es ueberhaupt PCI Geraete? */
/* (wird eigentlich durch die folgenden Funktionen schon abgedeckt) */
/* if (!pci_present ())
{
printk ("LATTICE PCI-Board: no pci-devices found.\n");
result = -ENODEV;
goto exit0;
}*/
/* Ist das LATTICE Board eingebaut? */
LATTICE_pci_dev.pci_dev = pci_find_device (PCI_VENDOR_ID_LATTICE,
PCI_DEVICE_ID_LATTICE_PCI, LATTICE_pci_dev.pci_dev);
if (LATTICE_pci_dev.pci_dev == NULL)
{
printk ("LATTICE PCI-Board: card not present\n");
result = -EIO;
goto exit0;
}
/* Aufwecken des PCI-Geraetes */
if (pci_enable_device (LATTICE_pci_dev.pci_dev))
{
printk ("LATTICE PCI-Board: unable to enable card\n");
result = -EIO;
goto exit0;
}
LATTICE_pci_dev.phys_addr = pci_resource_start (LATTICE_pci_dev.pci_dev, 0);
LATTICE_pci_dev.size = pci_resource_len (LATTICE_pci_dev.pci_dev, 0);
/* Belegen des I/O-Speichers */
if (!request_mem_region (LATTICE_pci_dev.phys_addr,
LATTICE_pci_dev.size,
LATTICE_PCI_NAME))
{
printk ("LATTICE PCI-Board: request_mem_region (0x%lx) failed\n",
LATTICE_pci_dev.phys_addr);
result = -EBUSY;
goto exit0;
}
LATTICE_pci_dev.virt_addr = ioremap (LATTICE_pci_dev.phys_addr,
LATTICE_pci_dev.size);
/* Untersuchen, ob die PCI-Karte ueber Interrupt-Funktion verfuegt */
/* (Register "Interrupt Pin" im PCI Configration Header) */
//pci_read_config_byte (LATTICE_pci_dev.pci_dev, PCI_INTERRUPT_PIN, &intr_pin);
//if (intr_pin == 0)
//{
// printk ("LATTICE PCI-Board: device doesn't support interrupts.\n");
// result = -EIO;
//goto exit1;
//}
/* Lesen der in der Konfigurationsphse zugewiesenen IRQ-Nummer */
/* (Register "Interrupt Line" im PCI Configuration Header */
pci_read_config_byte (LATTICE_pci_dev.pci_dev,
PCI_INTERRUPT_LINE,
&LATTICE_pci_dev.intr_line);
/////////////////////////////////////////////////////////////////////////////////////////////////
msi_data = 0x4100 |msi_ID;
msi_address_hi= 0x0;
msi_address_lo= 0x03;
//================ DMA Common Buffer (Consistent) Allocation ====================
// First see if platform supports 32 bit DMA address cycles (like what won't!)
if (pci_set_dma_mask(LATTICE_pci_dev.pci_dev, DMA_32BIT_MASK))
{
printk(KERN_WARNING "lattice_pci: init DMA not supported!\n");
//pBrd->hasDMA = FALSE;
}
else
{
//pBrd->hasDMA = TRUE;
printk(KERN_WARNING "lattice_pci: init DMA supported!\n");
dmaBufSize = DMA_BUFFER_SIZE;
dmaCPUAddr = pci_alloc_consistent(LATTICE_pci_dev.pci_dev, dmaBufSize, &dmaPCIBusAddr);
if (dmaCPUAddr == NULL)
{
printk(KERN_WARNING "lattice_pci: init DMA alloc failed! No DMA buffer.\n");
//pBrd->hasDMA = FALSE;
}
else
{
printk(KERN_WARNING "lattice_pci: init DMA alloc passed! DMA buffer.\n");
printk(KERN_INFO "lattice_pci: write msi_Data=%0x\n", msi_data);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x73,msi_address_hi);
pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x77,msi_address_lo);
pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x7B,0x4100);
////////////////////
pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x70,&msi_capability);
pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x73,&msi_address_hi);
pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x77,&msi_address_lo);
pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x7B,&msi_data);
///////////////////
printk(KERN_INFO "lattice_pci: Config space: MSI Capability =%0x\n", msi_capability);
printk(KERN_INFO "lattice_pci: Config space: Adress High =%0x\n", msi_address_hi);
printk(KERN_INFO "lattice_pci: Config space: Address Low =%0x\n", msi_address_lo);
printk(KERN_INFO "lattice_pci: Config space: Data Register =%0x\n", msi_data);
printk(KERN_INFO "lattice_pci: Config space Data =%0x\n", msi_data);
//msi_data = 0x4100 |msi_ID;
// msiaddr= 0
//u32 msi_data;
/* Enable the MSI interrupts */
if(pci_enable_msi(LATTICE_pci_dev.pci_dev)){
printk("LATTICE PCI-Board: unable to enable MSI\n");
result = -1;
goto msicleanup;
}
printk("LATTICE PCI-Board: MSI Enable \n");
/* Interrupt-Handler registrieren */
if (request_irq (LATTICE_pci_dev.intr_line,(irq_handler_t)LATTICE_pci_intr_handler,
IRQF_DISABLED, LATTICE_PCI_NAME, &LATTICE_pci_dev))
{
printk ("LATTICE PCI-Board: can't get assigned IRQ %d.\n", LATTICE_pci_dev.intr_line);
result = -EIO;
goto exit1;
}
/* Benutzer informieren */
printk("LATTICE PCI-Board: pci-card found at address 0x%lx, IRQ %d\n",
LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.intr_line);
return 0;
exit1:
iounmap (LATTICE_pci_dev.virt_addr);
release_mem_region (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size);
msicleanup:
/* Disable the MSI interrupts */
pci_disable_msi(LATTICE_pci_dev.pci_dev);
exit0:
return result;
}