[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Working PortA Interrupt Handling Driver



Just thought I would post a driver that worked for everybody.
Not really the finest example of code, but....

#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/tqueue.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/init.h>

#include <asm/segment.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/svinto.h>
#include <asm/io.h>

#define GPIOA_MAJOR 127

static struct timer_list porta_enable_timer;

static ssize_t gpioa_read(struct file *file, char *buf,
                         size_t count, loff_t *off);
static ssize_t gpioa_write(struct file *file, const char *buf,
                         size_t count, loff_t *off);
static int gpioa_ioctl(struct inode *inode, struct file *file,
                     unsigned int op, unsigned long arg);
static int gpioa_open(struct inode *inode, struct file *file);
static int gpioa_close(struct inode *inode, struct file *file);

static struct file_operations gpiod_fops = {
  read:    gpioa_read,   /* read    */
  write:   gpioa_write,  /* write   */
  ioctl:   gpioa_ioctl,  /* ioctl   */
  open:    gpioa_open,   /* open    */
  release: gpioa_close,  /* release */
};

static ssize_t gpioa_read(struct file *file, char *buf, size_t count, loff_t
*off) {
	return 0;
}

static ssize_t gpioa_write(struct file *file, const char *buf, size_t count,
loff_t *off) {
	return 0;
}

static int gpioa_ioctl(struct inode *inode, struct file *file,
              unsigned int op, unsigned long arg)
{
  switch (op) {
   default:
    return -EINVAL;
    break;
  }

  return 0;
}

static int gpioa_open(struct inode *inode, struct file *file)
{
  return 0;
}

static int gpioa_close(struct inode *inode, struct file *file)
{
  return 0;
}

static void porta_irq(int irq, void* dev_id, struct pt_regs *regs) {
	unsigned char porta_val;
	unsigned char mask;
	int i;

	// diable offending irq
	*R_IRQ_MASK1_CLR = 2;  // diables offending irqs

	printk("got a PortA IRQ\n");

	mod_timer(&porta_enable_timer,1); // wait a little
	return;
}

static void check_porta_enable_irq(unsigned long data) {
	unsigned long flags;
	unsigned char porta_poll;

	printk("I got a timeout\n");

	save_flags(flags);
	cli();

	porta_poll = *R_PORT_PA_DATA;
	porta_poll &= 0x02;		// just interested in the pin the button is connected
to
	if (porta_poll==0) {
		printk("reenabling irq\n");				// dont actually do it, just see the printk
//		*R_IRQ_MASK1_SET = 2; // PA 1 (The Button)
	} else {
//		printk("delaying\n");
		mod_timer(&porta_enable_timer,10);	// wait some more
	}
	restore_flags(&flags);
}

static int __init etrax_par_gpioa_init(void)
{
  printk("ETRAX 100LX GPIOA IO driver v0.1\r\n");

  if (register_chrdev(GPIOA_MAJOR, "GPIOA", &gpiod_fops)) {
    printk("unable to get major %d for GPIOA_MAJOR\n", GPIOA_MAJOR);
  }

  init_timer(&porta_enable_timer);
  porta_enable_timer.function = check_porta_enable_irq;

  if (request_irq(11,porta_irq,0,"gpioa PORTA IRQ",NULL)) {
    printk("unable to get gpioa PortA IRQ\n");
  }

  *R_IRQ_MASK1_SET = 2; // PA 1 (The Button)
  // this should cause an immediate interrupt - since the button is high
when not pressed...

  return 0;
}

module_init(etrax_par_gpioa_init);