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