/*
* This module was written by Stephen Nestinger for use with the
* DIO96 National Instrument Board under RTAI linux with RTHAL.
*/
/* Required Definitions */
#define MODULE
#define __KERNEL__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Uncomment for debugging */
//#define DEBUG
/* License */
MODULE_LICENSE("GPL");
/***************************
* Setup required variables
***************************/
static RT_TASK rt_task;
static RTIME task_period;
struct msg_struct msg;
unsigned char * baseptr0;
unsigned char * baseptr1;
static int DataPts = 0;
static int working = 0;
RTIME task_period_count = 0;
RTIME timer_period_count = 0;
/***************************/
static void task_code(int arg)
{
static int count = 0;
short int rtf = 0;
char outa = 0x00;
char outb = 0x00;
int n;
int i;
RTIME startTime;
#ifdef DEBUG
printk("RT-TASK Started\n");
#endif
while(1)
{
#ifdef DEBUG
printk("RT-TASK Suspended\n");
#endif
rt_task_suspend(&rt_task);
#ifdef DEBUG
printk("RT-TASK Resumed\n");
printk("\tDataPts = %d\n", DataPts);
printk("\tbuffer_size = %d\n", msg.buffer_size);
#endif
startTime = rt_get_time();
for(i=0; i= msg.buffer_size)
{
n = rtf_put(SEMEPHORE_FIFO, &rtf, 1);
rtf=(~rtf)&0x01;
count = 0;
}
rt_task_wait_period();
}
#ifdef DEBUG
printk("\ti = %d\n", i);
printk("\ttotal time = %u\n",
(unsigned long)count2nano(rt_get_time()-startTime));
#endif
DataPts = 0;
rtf = 0;
}
return;
}
static int fifo_handler(unsigned int fifo)
{
int retval;
if ((rtf_get(COMMAND_FIFO, &msg, sizeof(msg))) != 0)
{
switch(msg.command)
{
/* Start data reading thread */
case START_TASK:
#ifdef DEBUG
printk("START_TASK\n");
printk("\tDataPts: %d\n", (int) msg.dataPts);
#endif
writeb(msg.conf, CNFG_ADDR);
DataPts = msg.dataPts;
task_period_count = nano2count(100000);
timer_period_count = start_rt_timer(task_period_count);
#ifdef DEBUG
printk("Periodic_task: requested %u nanosec, got %u nanosecs\n",
(unsigned long)cout2nano(task_period_count),
(unsigned long)count2nano(timer_period_count));
#endif
retval = rt_task_make_periodic(&rt_task,
rt_get_time()+timer_period_count,
timer_period_count);
if (retval)
{
printk("Could not start task\n");
return retval;
}
break;
/* Suspend data reading thread */
case STOP_TASK:
#ifdef DEBUG
printk("STOP_TASK\n ");
#endif
rt_task_suspend(&rt_task);
break;
default:
printk("RT-Task: Bad Command\n");
return 0;
}
}
else
printk("Read from COMMAND_FIFO error.\n");
return 0;
}
/*************************************************************
* Detect and Configure the DIO96 Board
************************************************************/
int dio96_setup(void)
{
struct pci_dev *dev = NULL;
u32 base_addr1, base_addr0, pci_irq_line, offset, window_value;
u8 pci_cmd;
#ifdef DEBUG
printk("Begin dio96_setup()\n");
#endif
if(!pci_present())
return -ENODEV;
/* find PCI-DIO-96 in PCI slots */
dev = pci_find_device(DIO96_VENDOR, DIO96_ID, dev);
if(!dev)
{
printk("DIO96 not found on this machine.\n");
return -ENODEV;
}
#ifdef DEBUG
printk(" DIO96 device found.\n");
#endif
/*************************************************
* Disable Master/IO access, Enable memory access
* enables bus-mastering for device dev
**************************************************/
pci_set_master(dev);
pci_read_config_byte(dev, PCI_COMMAND, &pci_cmd);
pci_cmd |= PCI_COMMAND_MEMORY;
pci_cmd &= ~PCI_COMMAND_IO;
pci_cmd |= PCI_COMMAND_IO;
pci_cmd |= PCI_COMMAND_MASTER;
pci_cmd |= PCI_COMMAND_INVALIDATE;
pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
/***************************************************
* get base addresses for Mite and I/O register and
* IRQ line of board for version linux kernels 2.4.x
* and above
**************************************************/
base_addr1 = pci_resource_start(dev,1);
base_addr0 = pci_resource_start(dev,0);
/***************************************************
* get base addresses for Mite and I/O register and
* IRQ line of board for linux kernel 2.2.19
**************************************************/
/*
base_addr1 = dev->base_address[1];
base_addr0 = dev->base_address[0];
*/
pci_irq_line = dev->irq;
/* remap base addresses to virtual memory space*/
offset = base_addr1 & ~PAGE_MASK;
base_addr1 &= PCI_BASE_ADDRESS_MEM_MASK;
base_addr1 &= PAGE_MASK;
baseptr0 = ioremap(base_addr0, 1024*4);
baseptr1 = ioremap(base_addr1, 1024*4);
#ifdef DEBUG
printk(" IRQ = %d\n", pci_irq_line);
printk(" offset = 0x%x\n", offset);
printk(" base_addr_after_mask = 0x%x\n", base_addr1);
printk(" baseptr0 = 0x%x\n", baseptr0);
printk(" baseptr1 = 0x%x\n", baseptr1);
#endif
/*****************************************************
* Configure Mite
* The window value should calculated from the base
* addr before remapping
*****************************************************/
window_value = (0xffffff00 & base_addr1) | 0x00000080;
writel(0x0000aeae, (baseptr0+0x0340));
writel(window_value, (baseptr0+0x00c0));
/* Testing: write to the offset 0 of the area */
writeb(0x80,(baseptr1+0x03));
writeb(0x00,baseptr1);
#ifdef DEBUG
printk("*baseptr0 = 0x%x\n", readb(baseptr0));
printk("*(baseptr0+3) = 0x%x\n", readb(baseptr0+0x03));
printk("*baseptr1 = 0x%x\n", readb(baseptr1));
printk("*(baseptr1+3) = 0x%x\n", readb(baseptr1+0x03));
printk("End dio96_setup()\n");
#endif
return 0;
}
int init_module(void)
{
int retval;
printk("DIO96 Real-Time Module\n");
/*************************************************************
* Configure the DIO96
************************************************************/
if(dio96_setup() < 0)
{
printk("DIO96 Setup Failed. Exiting module.\n");
return 0;
}
/**************************************************************
* Create 4 FIFOs, two for data, one for commands from
* the user and one for semaphore.
**************************************************************/
#ifdef DEBUG
printk("DIO96: Create the FIFOS\n");
#endif
// Create the DATA_FIFO_1
retval = rtf_create(DATA_FIFO_1, DATA_SIZE);
if(retval)
{
printk("Could not create RT-FIFO %d\n", DATA_FIFO_1);
return retval;
}
// Clear out DATA_FIFO_1
rtf_reset(DATA_FIFO_1);
// Create the DATA_FIFO_2
retval = rtf_create(DATA_FIFO_2, DATA_SIZE);
if(retval)
{
printk("Could not create RT-FIFO %d\n", DATA_FIFO_2);
return retval;
}
// Clear out DATA_FIFO_2
rtf_reset(DATA_FIFO_2);
// Create the COMMAND_FIFO
retval = rtf_create(COMMAND_FIFO, 40);
if(retval)
{
printk("Could not create RT-FIFO %d\n", COMMAND_FIFO);
return retval;
}
// Clear out FIFO COMMAND
rtf_reset(COMMAND_FIFO);
// Create the SEMEPHORE_FIFO
retval = rtf_create(SEMEPHORE_FIFO, SEMEPHORE_SIZE);
if(retval)
{
printk("Could not create RT-FIFO %d\n", SEMEPHORE_FIFO);
return retval;
}
// Clear out SEMEPHORE_FIFO
rtf_reset(SEMEPHORE_FIFO);
/**************************************************************/
/**************************************************************
* Associate our handler task with the COMMAND FIFO. When
* data is written to this FIFO by the user process, this
* handler will be called.
**************************************************************/
retval = rtf_create_handler(COMMAND_FIFO, fifo_handler);
if(retval)
{
printk("Could not create RT-FIFO handler\n");
return retval;
}
/* Initialize the task structre */
retval = rt_task_init(&rt_task, task_code, 0, 1024,
RT_SCHED_LOWEST_PRIORITY, 0, 0);
if (retval)
{
printk("Could not init task\n");
return retval;
}
/* Setup the timer */
rt_set_periodic_mode();
retval = rt_task_resume(&rt_task);
if (retval)
{
printk("Could not start task\n");
return retval;
}
return 0;
}
void cleanup_module(void)
{
/* Remove the task and stop the timer */
stop_rt_timer();
rt_task_delete(&rt_task);
/* Remove our FIFOs */
rtf_destroy(DATA_FIFO_1);
rtf_destroy(DATA_FIFO_2);
rtf_destroy(COMMAND_FIFO);
rtf_destroy(SEMEPHORE_FIFO);
/* Unmap the PCI memory*/
iounmap(baseptr0);
iounmap(baseptr1);
printk("End of DIO96 module.\n");
return;
}