ts-7000
[Top] [All Lists]

[ts-7000] Cannot read PC104 from kernel space

To:
Subject: [ts-7000] Cannot read PC104 from kernel space
From: "elliotbuller" <>
Date: Sun, 25 Nov 2007 20:32:37 -0000
I'm having an issue reading data over the pc104 bus from a kernel
module. I am able to read just fine from a userspace app using mmap.
Please tell me what the difference is between the access I am doing in
userspace and kernel space. The externel hardware generates the
interrupt and I see it trap to the interrupt handler. At that point it
tries to do a read over the bus but it is not latching the data right.
I get random results as if I'm just reading random memory although I
do see the mem_r line strobe low. I know you can't use mmap in a
kernel module but from what I've read it sounded like the ISA memory
region could be accessed using __ioremap(). Any suggestions would be
great.
-Elliot
TS7300 - 2.4.26-ts11 #35

Here is my userspace app:

#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include "stdtypes.h"
#include "peekpoke.h"

/*
Other possible bases
0x21810000
0x21A00000
0x21A10000
*/

#define PC104_BASE 0x21A00000L

int passed=0, failed=0, reads=0;
uint16 expected=0x0;
int t_delay = 0;
clock_t begin, end;

delay( volatile int x )
{
        volatile int k=0;
        while( k < x ) k++;
}
int main(int argc, char **argv){
        uint16 reading;
        volatile uint16 *start;
        long seconds;
        uint32 count = 0;
        int fd = open("/dev/mem", O_RDWR|O_SYNC);
        start = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED,

          reading =  PEEK16((long)start);
          expected = reading + 1;

          while(count < 10000000)
          {
                reading =  PEEK16((long)start);
                if(reading == expected)
                {
                  passed++;
                  expected++;
                }
                else
                {
                  failed++;
                  expected=reading+1;
                }
                count++;
          }
          printf("%d READS\n---------\nPASSED: %d   FAILED: %d\n",
count, passed, failed);
        
        close(fd);
        return 0;
}

/***********************************/

Here is my kernel module:
// Linux Device Driver Template/Skeleton
// Kernel Module

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/ioport.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include "peekpoke.h"

#define PC104_MAJOR              63
#define PC104_NAME               "PC104"
#define PC104_INTERRUPT          22        // Corresponds to IRQ5
#define PC104_BASE               0x21A00000L
#define PC104_MEM_SIZE           4


MODULE_AUTHOR("Elliot Buller: Colorado State 2007");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PC104 Data Acquisition Card Driver");

extern void disable_irq (unsigned int irq);
static unsigned int counter = 0;
static int interruptcount = 0;
static volatile uint16_t *base;
static char string[150];
DECLARE_WAIT_QUEUE_HEAD(pc104_wait);
static int data_not_ready = 1;

static int pc104_open (struct inode *inode, struct file *file) {
  printk("pc104_open\n");
  return 0;
}

static int pc104_release (struct inode *inode, struct file *file) {
        printk("pc104_release\n");
        return 0;
}

static ssize_t pc104_read (struct file *file, char *buf,
                           size_t count, loff_t *ppos) {
  int len, err;
  
  // check if we have data - if not, sleep
  // wake up in interrupt_handler
  while (data_not_ready) {
    interruptible_sleep_on(&pc104_wait);
  }
  data_not_ready = 1;

  /* Add read code here */
  return len;
}

// write function called when to /dev/skeleton is written
static ssize_t pc104_write (struct file *file, const char *buf,
                            size_t count, loff_t *ppos) {
  int err;
  err = copy_from_user(string,buf,count);
  if (err != 0)
    return -EFAULT;
  counter += count;
  return count;
}


// interrupt handler
static int interrupt_handler(void)
{
  
  interruptcount++;
  printk(">>> PC104 BUS INT: interruptcount=%d\n", interruptcount);  
 
  printk("PC104 Samples: 0x%04X\n", PEEK16(base));

  /* Data ready. Wake up userspace process */
  data_not_ready = 0;
  wake_up_interruptible(&pc104_wait);
  
  return IRQ_HANDLED;
}

// define which file operations are supported
struct file_operations pc104_fops = {
        .owner  =       THIS_MODULE,
        .llseek =       NULL,
        .read   =       pc104_read,
        .write  =       pc104_write,
        .readdir =      NULL,
        .poll =         NULL,
        .ioctl  =       NULL,
        .mmap  =        NULL,
        .open =         pc104_open,
        .flush  =       NULL,
        .release =      pc104_release,
        .fsync  =       NULL,
        .fasync =       NULL,
        .lock  =        NULL,
        .readv  =       NULL,
        .writev =       NULL,
};

// initialize module (and interrupt)
static int pc104_init_module (void) {
  int i;
  int ret;
  printk("<1>Initializing PC104 module\n");
  
  i = register_chrdev (PC104_MAJOR, PC104_NAME, &pc104_fops);
  if (i != 0) return - EIO;
  
  // INIT INTERRUPT
  ret = request_irq(PC104_INTERRUPT, &interrupt_handler,
                    SA_INTERRUPT, "pc104_driver", NULL);
  
  /* Check to see if ISA memory in use */
  if (check_mem_region(PC104_BASE, PC104_MEM_SIZE)) {
    printk("pc104: memory already in use\n");
    return -EBUSY;
  }
  
  /* Request memory space */
  request_mem_region(PC104_BASE, PC104_MEM_SIZE, PC104_NAME);
  
  /* Warning: Cannot use ioremap as it adds offset */
  base = (volatile uint16_t*)__ioremap(PC104_BASE, PC104_MEM_SIZE, 0);
  if(base == NULL)
  {
    printk("Error mapping memory!\n");
    return -EBUSY;
  }
  
  printk("Memory mapped: 0x%08X\n", base);
  return 0;
}


// close and cleanup module
static void pc104_cleanup_module (void) {
  printk("<1>Cleaning up PC104 module\n");
  
  iounmap((void*)base);
  release_mem_region(base, PC104_MEM_SIZE);
  unregister_chrdev (PC104_MAJOR, PC104_NAME);
  disable_irq(PC104_INTERRUPT);
  free_irq(PC104_INTERRUPT, NULL);
  
}

module_init(pc104_init_module);
module_exit(pc104_cleanup_module);



 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/ts-7000/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/ts-7000/join
    (Yahoo! ID required)

<*> To change settings via email:
     
    

<*> To unsubscribe from this group, send an email to:
    

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/
 

<Prev in Thread] Current Thread [Next in Thread>
Admin

Disclaimer: Neither Andrew Taylor nor the University of NSW School of Computer and Engineering take any responsibility for the contents of this archive. It is purely a compilation of material sent by many people to the birding-aus mailing list. It has not been checked for accuracy nor its content verified in any way. If you wish to get material removed from the archive or have other queries about the archive e-mail Andrew Taylor at this address: andrewt@cse.unsw.EDU.AU