Hi,
I have some questions about the linux kernel and the mainframe of my driver
(They still not working but I believe... ) If someone have time, he can
continue my learning!
1- What is the read (readb (8bits), readw (16 bits), ... (32bits)) function
(read memory mapped PCI) for a unsigned integer 32bits ? readdw?
2- What is the key word "volatile" in C? It's not wrote in my C book.
3- Before configure my timer/counter 82C54, I need a time delay. I actually
use rtl_delay. My task is not critical (during the configuration) can use
a since sleep in the rtl process?
4- I will use a thread for driver the communication/control of my ISR (I
will add other functionalitys later, the source code is in attachment but
not working/not tested/not compiled). I do this because the IRQ is timed by
the device (data acquisition board). This process need to be real-time...
but with a very low priority. How work the priority? by relative priority
level (as in java)? Can I make the setup of this rt-thread with the same
priority as the other none rt-thread?
5- Where is the declaration of the structure sched_param? I am interest to
look at setup possibility.
Thanks a lot,
I appreciate your help.
Stephane Bouchard
[EMAIL PROTECTED]
/* ************************************************************************ */
/* ComputerBoard PCI-DAS1602/16 DAQ Board Driver */
/* Stephane Bouchard */
/* [EMAIL PROTECTED] / [EMAIL PROTECTED] */
/* Laboratoire de Recherche en BioIngenierie */
/* Universite Laval, Quebec, Canada */
/* */
/* Special thanks to all people from RT-Linux mailing list */
/* only the need functionality for my project is implemented... you can */
/* continue. */
/* ************************************************************************ */
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <rtl_core.h>
#include <trl_time.h>
#include <rtl_sched.h>
#include <rtl_fifo.h>
#include <rtl_sync.h>
#include "common.h"
/* ************************************************************************ */
/* global variables */
/* ************************************************************************ */
static struct BoardInfo board;
static union intReg intRegStatus;
static uint16 *dataRead=NULL;
static uint32 countIRQ;
pthread_t thread;
uint32 numberscan;
uint8 countChannel;
uint16 regIntCp;
/* ************************************************************************ */
/* global variables and macro commands for FP operation in ISR */
/* ************************************************************************ */
uint32 cr0;
uint32 linux_fpe[27];
uint32 task_fpe[27];
#define save_cr0_and_ctls(x) __asm__ __volatile__ ("movl %%cr0,%0; clts" :"=r" (x))
#define restore_cr0(x) __asm__ __volatile__ ("movl %0,%%cr0": :"r" (x))
#define save_fpenv(x) __asm__ __volatile__ ("fnsave %0" : "=m" (x))
#define restore_fpenv(x) __asm__ __volatile__ ("frstor %0" : "=m" (x))
/* ************************************************************************ */
/* volatile void CBISR(); */
/* This function is call by the interrupt */
/* args in : */
/* args out : */
/* global variables : struct BoardInfo board */
/* fifo */
/* Note: */
/* ************************************************************************ */
volatile void CBISR() {
/* disable the irq of the device during the isr */
rt_disable_irq(board.irq);
/* look if the interrupt come from this board */
if (!readdw(board.badr0+0x00000038)&0x00820000) {
/* Start of floating point operation */
save_cr0_and_ctls(cr0);
save_fpenv(linux_fpe);
restore_fpenv(task_fpe);
/* read the datas from register */
for (countChannel=0;countChannel<CHANNELNUMBER;countChannel++) {
dataRead[countChannel]=(uint16)(readw(board.badr2)*0.5);
};
/* put controller and out here */
/* Stop of floating point operation */
save_fpenv(task_fpe);
restore_fpenv(linux_fpe);
restore_cr0(cr0);
/* send data out by the fifo */
rtf_put(FIFO_data, dataRead, CHANNELNUMBER*2);
/* check the number of scan and ... */
if (countIRQ<numberscan) {
/* increase the number of scan */
countIRQ++;
/*clear the interrupt */
writew(0x0085, board.badr1);
} else {
/* stop pacer */
writew(0x0000,board.badr1+0x0002);
/* clear ADC fifo */
writew(0x0000,board.badr2+0x0002); /* write junk */
};
};
/* enable the irq of this device */
rt_enable_irq(board.irq);
/* share irq with linux and other devices */
rtl_pend_linux_irq(board.irq)
};
/* ************************************************************************ */
/* int16 CBFind(void); */
/* This function look for the board. If find, set all information in struct */
/* BoardInfo board. */
/* args in : */
/* args out : int16 status */
/* status : status of the function */
/* global variables : struct BoardInfo board */
/* ************************************************************************ */
int16 CBInit() {
extern struct pci_dev *pdev=NULL;
/* Check if a pci bus is present */
if (!pci_present()) {
return NOPCIBUS;
};
/* look for a ComputerBoards PCI-DAS1602/16 */
if pdev=pci_find_device(VENDORID, BOARDID, pdev)) {
/* Map the pci memory in the cpu memory */
board.badr0=(uint32 *) ioremap(pdev->base_address[0], 0x0004 );
if(board.badr0==NULL) return IOREMAPERR;
board.badr1=(uint16 *) ioremap(pdev->base_address[1], 0x000A);
if(board.badr1==NULL) return IOREMAPERR;
board.badr2=(uint16 *) ioremap(pdev->base_address[2], 0x0004);
if(board.badr2==NULL) return IOREMAPERR;
board.badr3=(uint8 *) ioremap(pdev->base_address[3], 0x000D);
if(board.badr3==NULL) return IOREMAPERR;
board.badr4=(uint16 *) ioremap(pdev->base_address[4], 0x0004);
if(board.badr4==NULL) return IOREMAPERR;
/* setup informations in the struct BoardInfo board */
board.irq=pdev->irq;
board.vendorID=VENDORID;
board.boardID=BOARDID;
} else {
return NOPCIDAS160216;
};
};
/* ************************************************************************ */
/* int16 CBConfigure(double frequency); */
/* This function configure the board and set the frequency */
/* args in : double frequency */
/* frequency : sampling frequency of the board */
/* args out : int16 status */
/* status : status of the function */
/* global variables : struct BoardInfo board */
/* ************************************************************************ */
int16 CBConfigure(double frequency) {
/*allocate to backup the irq lines status */
rtl_irqstate_t irqStatus;
/* disable interrupts on the CPU */
rtl_no_interrupts(irqStatus);
/* configure the isr handler and get the interrupt */
if(!rtl_request_irq(board.irq, &CBISR)) {
/* setup variable for make the computation of the diviser frequency */
uint32 diviserFrequency;
uint8 *diviserFreq;
diviserFreq=&diviserFrequency;
/* disable everything first */
writew(0x0000,board.badr1)
/* stop pacer */
writew(0x0000,board.badr1+0x0002);
/* clear ADC fifo */
writew(0x0000,board.badr2+0x0002); /* write junk */
/* setup pacer for internal pacer clock */
/* 8254 - counter 1 mode 2 least significant bit */
writeb(0x0054,board.badr3+0x0003);
rtl_delay(10);
/* 8254 - counter 2 mode 2 least significant bit */
writeb(0x0094,board.badr3+0x0003);
rtl_delay(10);
/* compute the diviser for 82C54 (Pacer source at 10Mhz and 8 channels)*/
diviserFrequency=(long)(10000000/frequency);
/* write the ADC pacer diviser for generate the frequency */
writeb(*(diviserFreq+4),board.badr3+0x0001); /* 0-7 bits */
rtl_delay(10);
writeb(*(diviserFreq+3),board.badr3+0x0001); /* 8-15 bits */
rtl_delay(10);
writeb(*(diviserFreq+2),board.badr3+0x0002); /* 16-23 bits */
rtl_delay(10);
writeb(*(diviserFreq+1),board.badr3+0x0002); /* 24-32 bits */
rtl_delay(10);
/* configure the dio */
/* port A out, port B in, port C up out, port C low in */
writeb(0x0082,board.badr3+0x0007);
/* setup trigger control */
/* No trigger set, burst mode select 10Mhz source fro counter 0*/
writew(0x0020,board.badr1+0x0004);
/*enable the acquisition interrupt */
writew(0x0005, board.badr1);
/* setup the irq as real-time irq */
rtl_hard_enable_irq(board.irq);
} else {
return IRQREQUESTERR;
};
/* restore the interrupts for the cpu */
rtl_restore_interrupts(irqStatus);
return NOERROR;
};
/* ************************************************************************ */
/* int16 CBStart(); */
/* This function start the acquisition and the control loop */
/* args in : */
/* args out : int16 status */
/* status : status of the function */
/* global variables : struct BoardInfo board */
/* ************************************************************************ */
int16 CBStart() {
/*reset the number of int loop */
countIRQ=0;
/* clear ADC fifo */
writew(0x0000,board.badr2+0x0002); /* write junk */
/* setup the MUX and the control register */
/* diff +/- 5 Volts, internal 82C54 Counter/Timer (10 Mhz) */
/* and 8 channels */
writew(0x1170,board.badr1+0x0002);
return NOERROR;
};
/* ************************************************************************ */
/* int16 CBStop(); */
/* This function stop the acquisition and the control loop */
/* args in : */
/* args out : int16 status */
/* status : status of the function */
/* global variables : struct BoardInfo board */
/* ************************************************************************ */
int16 CBStop() {
/* stop pacer */
writew(0x0000,board.badr1+0x0002);
/* clear ADC fifo */
writew(0x0000,board.badr2+0x0002); /* write junk */
return NOERROR;
};
/* ************************************************************************ */
/* int16 CBClose(); */
/* This function close the device, please use CBStop before */
/* args in : */
/* args out : int16 status */
/* status : status of the function */
/* global variables : struct BoardInfo board */
/* ************************************************************************ */
int16 CBClose() {
/* disable the burst mode */
writew(0x0000, board.badr1+0x0004);
/* disable the acquisition interrupt */
writew(0x0000, board.badr1);
/* free irq */
if(board.irq!=0) rtl_free_irq(board.irq);
board.irq=0;
/* unmap all allocate memory mapped by the precessor*/
iounmap(board.badr0);
iounmap(board.badr1);
iounmap(board.badr2);
iounmap(board.badr3);
iounmap(board.badr4);
};
/* ************************************************************************ */
/* void *CBModuleRT(); */
/* This function send order to the interrupt. */
/* args in : */
/* args out : */
/* ************************************************************************ */
void *CBRTModule() {
uint8 command; /* command to execute */
double frequency; /* frequency of the acquisition */
uint32 scan; /* number of scans to acquire */
uint16 status; /* status of the command */
struct sched_param param;
param.sched_priority=1;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
pthread_make_periodic_np(pthread_self(), gethrtime(), 50);
while(1) {
pthread_wait_np();
switch rtf_get(FIFO_OUT_DATA,&command,sizeof(uint8)) {
case CB_CONFIGURE:
rtf_get(FIFO_COMMAND,&frequency,sizeof(double));
rtf_get(FIFO_COMMAND,&scan,sizeof(uint32));
/* init the status for compute the number of scan */
countIRQ=0;
numberscan=scan;
/* allocate the space for the read data */
dataRead=kmalloc(dataRead,CHANNELNUMBER,GFP_KERNEL);
/* find the PCI DAQ board */
status=CBInit();
rtf_get(FIFO_STATUS,&status,sizeof(uint16));
/* configure the PCI DAQ board */
status=CBConfigure(frequency);
rtf_get(FIFO_STATUS,&status,sizeof(uint16));
return;
case CB_START:
status=CBStart();
rtf_get(FIFO_STATUS,&status,sizeof(uint16));
return;
case CB_STOP:
status=CBStop();
rtf_get(FIFO_STATUS,&status,sizeof(uint16));
return;
case CB_CLOSE:
/* disable acquisition */
CBStop();
/* close the device */
CBClose();
/* close the fifo */
rtf_destroy(FIFO_OUT_DAT);
/* free the memory */
if(dataRead!=NULL) kfree(dataRead);
return;
default:
rtl_printf("Real time task unknown");
return;
};
};
return 0;
};
/* ************************************************************************ */
/* void CBInitModule(); */
/* This function init the module to communicate with display program. */
/* args in : */
/* args out : */
/* ************************************************************************ */
int16 init_module(void) {
pthread_attr_t attr;
struct sched_param sched_param;
/* setup the fifo */
rtf_destroy(FIFO_COMMAND);
rtf_create(FIFO_COMMAND,FIFO_COMMAND_SIZE);
rtf_destroy(FIFO_STATUS);
rtf_create(FIFO_STATUS,FIFO_STATUS_SIZE);
rtf_destroy(FIFO_OUT_DATA);
rtf_create(FIFO_OUT_DATA,FIFO_OUT_DATA_SIZE);
return pthread_create (&thread, NULL, start_routine, 0);
};
/* ************************************************************************ */
/* void cleanup_module(void); */
/* This function clear the communication module. */
/* args in */
/* args out : */
/* ************************************************************************ */
void cleanup_module(void)
rtf_destroy(FIFO_COMMAND);
rtf_destroy(FIFO_STATUS);
rtf_destroy(FIFO_OUT_DATA);
pthread_delete_np(thread);
};
#ifndef _COMMON_
#define _COMMON_
/* Type ... for non familar with Linux */
#define int8 i8
#define int16 i16
#define int32 i32
#define uint8 u8
#define uint16 u16
#define uint32 u32
/* error list */
#define NOERROR 00
#define NOPCIBUS 01
#define NOPCIDAS160216 02
#define IOREMAPERR 03
#define ERRASIGNISR 04
#define IRQREQUESTERR 05
#define FIFOERR 06
#define DATAREADERR 07
/* define the code number for the inter-process message */
#define CB_CONFIGURE 01
#define CB_START 02
#define CB_STOP 03
#define CB_CLOSE 04
/* ComputerBoards PCI-DAS1602/16 definition*/
#define VENDORID 0x1307
#define BOARDID 0x0001
/* define the fifo */
#define FIFO_OUT_DATA 3
#define FIFO_OUT_DATA_NAME "dev/rtf3"
#define FIFO_OUT_DATA_SIZE 0x1000
#define FIFO_COMMAND 4
#define FIFO_COMMAND_NAME "dev/rtf4"
#define FIFO_COMMAND_SIZE 0x0100
#define FIFO_STATUS 5
#define FIFO_STATUS_NAME "dev/rtf5"
#define FIFO_STATUS_SIZE 0x0100
/* define the number of channel */
#define CHANNELNUMBER 8
/* define a structure to stock the board informations */
struct BoardInfo {
uint32 *badr0;
uint16 *badr1;
uint16 *badr2;
uint8 *badr3;
uint16 *badr4;
uint8 irq;
uint16 vendorID;
uint16 boardID;
} board;
#endif