RE: Invalid module format?

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

 



My drivers are inline in this mail.  I'm still having this problem with
the 2.6.16 kernel as where I'm not having it with the 2.6.15 kernel --
and it's the same source code, compiled the same way.

Also, I'm still having difficulties getting this driver to work
correctly so any help would be great!

-->
/usr/src/redhat/BUILD/kernel-2.6.16.16/linux-2.6.16.16/drivers/mvp/mvp_r
tc.c

static const char *rtc_c = "$Id: mvp_rtc.c,v 1.3 2006/04/18 21:20:36
brian Exp brian $ (c) MVP ";

#include <asm/io.h>		/* ioremap */
#include <asm/uaccess.h>	/* put_user */
#include <linux/config.h>	/* access CONFIG_PCI macro */
#include <linux/fs.h>
#include <linux/interrupt.h>	/* request/free_irq */
#include <linux/mm.h>		/* memory mapping */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>		/* kmalloc() */
#include <linux/types.h>

#include "dev/rtc.h"
#include "rtcsoft.h"

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#ifndef CONFIG_PCI
#error "This driver REQUIRES PCI support"
#endif

#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define
MODVERSIONS /* force it on */ #endif

#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif

#ifdef CONFIG_DEVFS_FS
devfs_handle_t rtc_devfs_dir;
#endif

#define TYPE(dev)   (MINOR(dev) >> 4)  /* high nibble */
#define NUM(dev)    (MINOR(dev) & 0xf) /* low  nibble */

#define kOneByteShift 8

extern void ibb_rtc_wakeup(void);
irqreturn_t rtc_intr(int irq, void *dev_id, struct pt_regs *regs);

static RtcSoftDev *RtcSoft[kNrtc];

#define DEBUG

#ifdef DEBUG
#define debug_out(msg)          { printk msg; }
#else
#define debug_out(msg)
#endif

static void
lock_rtc(RtcSoftDev *rtc_sp, unsigned long *flags, const char *where) {
    debug_out(("lock_rtc(%d): %s:\n", rtc_sp->dev_num, where));
    spin_lock_irqsave(&rtc_sp->mutex, *flags);
    debug_out(("lock_rtc(%d): Done %s:\n", rtc_sp->dev_num, where)); }

static void
unlock_rtc(RtcSoftDev *rtc_sp, unsigned long *flags, const char *where)
{
    debug_out(("unlock_rtc(%d): %s:\n", rtc_sp->dev_num, where));
    spin_unlock_irqrestore(&rtc_sp->mutex, *flags);
    debug_out(("unlock_rtc(%d): %s:\n", rtc_sp->dev_num, where)); }

static void
init_rtc_soft_state(void)
{
    int i;

    for (i = 0; i < kNrtc; i++) {
	RtcSoft[i] = NULL;
    }
}

static int
alloc_rtc_soft_state(void)
{
    int i;

    for (i = 0; i < kNrtc; i ++) {
	if (RtcSoft[i] == NULL) {
	    RtcSoft[i] = kmalloc(sizeof(RtcSoftDev), GFP_KERNEL);

	    if (RtcSoft[i] == NULL) {
		debug_out(("alloc_rtc_soft_state: out of memory.\n"));
		return(-1);
	    }

	    debug_out(("alloc_rtc_soft_state: return %d\n", i));
	    return(i);
	}
    }

    return(-1);
}

/*
 * There may be a better way to do this!
 *
 * I need to make sure the data I initialized in rtc_probe()
 * for device "X"  is the same data I use in rtc_open().
 *
 * I could use the minor numbers, but I have to trust that
 * the 'load' script for the rtc device is written correctly,
 * since that's where minor numbers are assigned.
 *
 * So I'm using the major numbers.  It's a little slower, since
 * major  numbers tend to be >200 I'm not just going to use
 * them as indexes into my array.  Instead I'm going though
 * all the devices looking for the matching major.
 *
 * My concern, frankly, is that no other drivers seem to be
 * using this method.  But it seems the only foolproof way
 * to keep the data with the device
 */

static int
find_rtc_soft_state(int rtc_major)
{
    int i;

    debug_out(("find_rtc_soft_state: major %d\n", rtc_major));

    for (i = 0; i < kNrtc; i++) {
	if (RtcSoft[i] != NULL) {
	    if( rtc_major == RtcSoft[i]->rtc_major) {
		debug_out(("find_rtc_soft_state: return %d\n", i));

		return(i);
	    }
	}
    }

    debug_out(("Can't find matching soft_state %d!\n", rtc_major));
    return(-1);
}

static void
free_rtc_soft_state(int i)
{
    if (RtcSoft[i] == NULL)
	return;

    debug_out(("free_rtc_soft_state(%d):\n", RtcSoft[i]->dev_num));

    kfree(RtcSoft[i]);
    RtcSoft[i] = NULL;

    return;
}

ssize_t
rtc_read(struct file *filp, char * buf, size_t count, loff_t *f_pos) {
    return(-EINVAL);
}

ssize_t
rtc_write(struct file *filp, const char *buf, size_t count, loff_t
*f_pos) {
    return(-EINVAL);
}

int
rtc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long __user arg) {
    RtcSoftDev *rtc_sp = filp->private_data;
    RtcStrobes rtc_light;

    struct timeval tv;

    u_long ecounts;
    u_long flags;

    int retval = 0;

    uint16_t i;
    uint16_t light_mask;

    uint32_t control_reg;
    uint32_t fireoff;
    uint32_t fireon;
    uint32_t reset;
    uint32_t set;
    uint32_t strobe_timer;
    uint32_t strobe_timer_mask;
    volatile uint32_t StartInspecting;

    if (rtc_sp == NULL) {
	debug_out(("rtc_ioctl: Soft Info Lost\n"));
	return(-EFAULT);
    }

    switch(cmd) {
	case RTCBONVOYAGE:
	    debug_out(("RTCBONVOYAGE\n"));
	    do_gettimeofday(&tv);

	    lock_rtc(rtc_sp, &flags, "RTCBONVOYAGE");

	    rtc_sp->shared_host_mem->ntimestamp = tv.tv_sec;
	    rtc_sp->snap_int_virt[kLastSnapLoc] = FIRST_SCAN;
	    StartInspecting = rtc_sp->snap_int_virt[kLastSnapLoc];

	    unlock_rtc(rtc_sp, &flags, "RTCBONVOYAGE");

	    debug_out(("RTCBONVOYAGE - DONE\n"));
	    break;

	case RTCWAKEUP:
	    debug_out(("RTCWAKEUP\n"));
	    ibb_rtc_wakeup();

	    debug_out(("RTCWAKEUP - DONE\n"));
	    break;


	case RTC_STROBEPROG_ON:
	    debug_out(("RTC_STROBEPROG_ON\n"));

	    if (copy_from_user((void *)rtc_light, 
		    (const void *)__user arg,
		    sizeof(RtcStrobes)))
	    {
		debug_out(("rtc_ioctl: can't copy RtcStrobes %lx %d\n",
			arg, sizeof(RtcStrobes)));

		return(EFAULT);
	    }

	    lock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_ON");

	    light_mask = 0;
	    strobe_timer = 0;

	    for (i = 0; i < kMaxRtcRings; i++) {
		if (rtc_light[i].hw_time > -1) {
		    debug_out(("rtc_ioctl: Enter time 0x%x for ring
%d\n",
			    rtc_light[i].hw_time,i));

		    light_mask |= (1 << (i));

		    strobe_timer_mask = rtc_light[i].hw_time;
		    strobe_timer_mask = strobe_timer_mask <<(i *
kOneByteShift);

		    strobe_timer = strobe_timer | strobe_timer_mask;
		}
	    }

	    *(rtc_sp->strobe_virt) = strobe_timer;
	    control_reg = *(rtc_sp->control_virt);

	    /* turn off all lights before putting in the ones we want */
	    control_reg &= ~ RCR_ALLLIGHTS;

	    if (light_mask == 0) {
		control_reg &= ~RCR_STROBEPROG;
	    }

	    else {
		light_mask = light_mask << 4;
		control_reg |= RCR_STROBEPROG;
		control_reg |= light_mask;
	    }

	    *(rtc_sp->control_virt) = control_reg;
	    unlock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_ON");

	    debug_out(("rtc_ioctl:control_reg at %#x\n", control_reg));
	    debug_out(("rtc_ioctl:strobe_reg at %#x\n", strobe_timer));

	    debug_out(("RTC_STROBEPROG_ON - DONE\n"));
	    break;

	case RTC_STROBEPROG_OFF:
	    /* set byte 0 in control reg to 0 */
	    debug_out(("RTC_STROBEPROG_OFF\n"));

	    lock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_OFF");
	    *(rtc_sp->control_virt) &= ~RCR_ALLLIGHTS;

	    debug_out(("rtc_ioctl:control_reg at %#x\n",
		*(rtc_sp->control_virt)));

	    *(rtc_sp->control_virt) &= ~RCR_STROBEPROG;

	    debug_out(("rtc_ioctl:control_reg at %#x\n",
		    *(rtc_sp->control_virt)));

	    unlock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_OFF");

	    debug_out(("RTC_STROBEPROG_OFF - DONE\n"));
	    break;

	case RTCFIRESTROBE:
	    /* set and reset bit 1 in control register */
	    debug_out(("RTCFIRESTROBE\n"));

	    lock_rtc(rtc_sp, &flags, "RTCFIRESTROBE");

	    fireoff = *(rtc_sp->control_virt);
	    fireon = fireoff | RCR_FIRESTROBE;

	    *(rtc_sp->control_virt) = fireon;
	    *(rtc_sp->control_virt) = fireoff;

	    unlock_rtc(rtc_sp, &flags, "RTCFIRESTROBE");

	    debug_out(("RTCFIRESTROBE - DONE\n"));
	    break;

	case RTCSTARTECOUNT:
	    /* 
	     * we need to set this bit so the encoder counts will be
	     * available to our encoder_regp regisert.  
	     */

	    debug_out(("RTCSTARTECOUNT\n"));

	    lock_rtc(rtc_sp, &flags, "RTCSTARTECOUNT");
	    *(rtc_sp->control_virt) |= RCR_ECOUNTON;
	    unlock_rtc(rtc_sp, &flags, "RTCSTARTECOUNT");

	    debug_out(("RTCSTARTECOUNT - DONE\n"));
	    break;

	case RTCGETECOUNT:
	    debug_out(("RTCGETECOUNT\n"));

	    lock_rtc(rtc_sp, &flags, "RTCGETECOUNT");
	    ecounts = *(rtc_sp->encoder_virt);

	    if (put_user(ecounts, (unsigned long *)__user arg)) {
		debug_out(("rtc_ioctl: can't copy encoder counts %lx
%d\n",
			ecounts, sizeof(long)));

		retval = -EFAULT;
	    }

	    /*
	     * clear the bit
	     */

	    *(rtc_sp->control_virt) &= ~RCR_ECOUNTON;
	    unlock_rtc(rtc_sp, &flags, "RTCGETECOUNT");

	    debug_out(("RTCGETECOUNT - DONE\n"));
	    break;

	case RTCRESETSNAP:
	    /* 
	     * if there has been an estop or a software crash, it's
possible
	     * the RTC state machine has gotten confused.  Setting and
reseting
	     * bit 15 will clear the state machine so it's ready for new
	     * inspections 
	     */

	    debug_out(("RTCRESETSNAP\n"));

	    lock_rtc(rtc_sp, &flags, "RTCRESETSNAP");
	    reset = *(rtc_sp->control_virt);
	    set = reset | RCR_SRESET;

	    *(rtc_sp->control_virt) = set;
	    *(rtc_sp->control_virt) = reset;

	    unlock_rtc(rtc_sp, &flags, "RTCRESETSNAP");

	    debug_out(("RTCRESETSNAP - DONE\n"));
	    break;

	case RTC_STAGE_NON_LINEAR:
	    /*
	     * change the dig cam compensation distance for non-linear
	     * stages, which have fewer encoder counts per inch
	     */

	    debug_out(("RTC_STAGE_NON_LINEAR\n"));

	    lock_rtc(rtc_sp, &flags, "RTC_STAGE_NON_LINEAR");
	    *(rtc_sp->control_virt) |= RCR_COMPSIZE;
	    unlock_rtc(rtc_sp, &flags, "RTC_STAGE_NON_LINEAR");

	    debug_out(("RTC_STAGE_NON_LINEAR - DONE\n"));
	    break;

	case RTCVERSION:
	    debug_out(("RTCVERSION\n"));

	    lock_rtc(rtc_sp, &flags, "RTCVERSION");

	    if (put_user(kRtcVersion, (unsigned long *)__user arg)) {
		debug_out(("rtc_ioctl: can't copy Version info %ld\n",
			kRtcVersion));

		retval = -EFAULT;
	    }

	    unlock_rtc(rtc_sp, &flags, "RTCVERSION");

	    debug_out(("rtc_ioctl: COPIED Version info %ld\n",
kRtcVersion));
	    debug_out(("RTCVERSION - DONE\n"));

	    break;

	default:
	    debug_out(("rtc_ioctl: unknown case: %d\n", cmd));
	    debug_out(("RTC---WTF\n"));

	    retval = -ENOTTY;
    }

    return(retval);
}

/*
 * just make sure the area mmap is requesting falls within
 * valid areas for the RTC card
 */

/* our off - 0x20000
 * our phys_off - 0x20000
 * our phys_diff - 0x20000
 */

int
rtc_mmap(struct file *filep, struct vm_area_struct *vma) {
    RtcSoftDev *rtc_sp = filep->private_data;

    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - vma->vm_start;
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long page = ((rtc_sp->iobase + offset) >> PAGE_SHIFT);

    if (offset > __pa(high_memory) || (filep->f_flags & O_SYNC)) {
	vma->vm_flags |= VM_IO;
    }

    vma->vm_flags |= VM_RESERVED;

    if (offset == RTC_SNAP_INTERVAL_OFFSET) {
	debug_out(("RTC_SNAP_INTERVAL_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_DIGIO_OFFSET) {
	debug_out(("RTC_DIGIO_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_STROBE_TIMER_OFFSET) {
	debug_out(("RTC_STROBE_TIMER_OFFSET: %x\n", offset));


	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));


	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_CONTROL_REG_OFFSET) {
	debug_out(("RTC_CONTROL_REG_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}

    }

    else if (offset == RTC_ENCODER_CNT_OFFSET) {
	debug_out(("RTC_ENCODER_CNT_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_GRAPHICS_REG_OFFSET) {
	debug_out(("RTC_GRAPHICS_REG_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_CY545_TRANS_OFFSET) {
	debug_out(("RTC_CY545_TRANS_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_CY545_CONTROL_OFFSET) {
	debug_out(("RTC_CY545_CONTROL_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_GRAPHICS_MEM_OFFSET) {
	debug_out(("RTC_GRAPHICS_MEM_OFFSET: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else if (offset == RTC_COMMON_VADDR) {
	debug_out(("RTC_COMMON_VADDR: %x\n", offset));

	while (size > 0) {
	    debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
	    	start, size, offset, page));

	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
	    	size -= PAGE_SIZE;
	    } else {
	    	size = 0;
	    }
	}
    }

    else {
	debug_out(("RTC_???_OFFSET --- WE'RE BROKEN --- %x\n", offset));
    }

    return(0);
}

int
rtc_open(struct inode *inode, struct file *filep) {
    RtcSoftDev *rtc_sp;
    int dev_num;

    int major = MAJOR(inode->i_rdev);
    int minor = MINOR(inode->i_rdev);

    /*
     * the type and num values are only valid if we are not using devfs.
     * hmm - sounds bad
     */

    /*
     * assign the private data so we can access it later
     * ( in read, write, ioctl, etc );
     */

    debug_out(("rtc_open: major %d minor %d\n", major, minor));
    dev_num = find_rtc_soft_state(major);

    if (dev_num < 0) {
	debug_out(("rtc_open: dev_num %d failed\n", dev_num));
    	return(-1);
    }

    rtc_sp = RtcSoft[dev_num];
    filep->private_data = rtc_sp;

    debug_out(("rtc opened by %s pid %d PAGE_SIZE %#lx\n",
	    current->comm, current->pid, PAGE_SIZE));

    return(0);
}

int
rtc_close( struct inode *inode, struct file *filep ) {
    return(0);
}

struct file_operations rtc_fops = {
    read:	rtc_read,
    write:	rtc_write,
    ioctl:	rtc_ioctl,
    mmap:	rtc_mmap,
    open:	rtc_open,
    release:	rtc_close,
};

static int
free_rtc_usr_shared(RtcSoftDev *rtc_sp)
{
    unsigned long virt_addr;
    struct page *page;

    /* unreserve all pages */

    for (virt_addr = (unsigned long) rtc_sp->shared_host_mem; 
	virt_addr < (unsigned long) rtc_sp->shared_host_mem +
RTC_COMMON_SIZE;
	virt_addr+=PAGE_SIZE)
    {
    	page = virt_to_page(virt_addr);
	ClearPageReserved(page);

	// atomic_set(&page->_count, 1);
	free_page(virt_addr);
    }

    if (rtc_sp->shared_host_mem) {
	rtc_sp->shared_host_mem = NULL;
    }

    return(0);
}

static int
alloc_rtc_usr_shared(RtcSoftDev *rtc_sp) {
    unsigned long virt_addr;
    int order = 0;

    /* 
     * get a memory area with kmalloc and aligned it to a page. This
area
     * will be physically contigous
     */

    while (RTC_COMMON_SIZE > (PAGE_SIZE * (1 << order))) {
    	order++;
    }

    rtc_sp->shared_host_mem = (RtcShared *)__get_free_pages(GFP_KERNEL,
order);

    if (rtc_sp->shared_host_mem == NULL) {
	debug_out(("alloc_rtc_usr_shared: out of memory.\n"));
	return(-1);
    }

    for (virt_addr = (unsigned long)rtc_sp->shared_host_mem; 
	    virt_addr < (unsigned
long)rtc_sp->shared_host_mem+RTC_COMMON_SIZE;
	    virt_addr += PAGE_SIZE)
    {
	/* reserve all pages to make them remapable */
	SetPageReserved(virt_to_page(virt_addr));
    }

    return(0);
}

static void
free_all_mappings(RtcSoftDev *rtc_sp)
{
    if (rtc_sp->snap_int_virt != NULL) {
	iounmap(rtc_sp->snap_int_virt);
	rtc_sp->snap_int_virt = NULL;
    }

    /*
     * we can call release_mem_region() without checking anything -
     * if the region hasn't been requested, the function will
     * just exit with an error message.
     * ( unlink iounmap() )
     */

    release_mem_region(rtc_sp->snap_int_phys, rtc_sp->snap_int_size);
    if (rtc_sp->digio_virt != NULL) {
	iounmap(rtc_sp->digio_virt);
	rtc_sp->digio_virt = NULL;
    }

    release_mem_region(rtc_sp->digio_phys, rtc_sp->digio_size);
    if (rtc_sp->strobe_virt != NULL) {
	iounmap(rtc_sp->strobe_virt);
	rtc_sp->strobe_virt = NULL;
    }

    release_mem_region(rtc_sp->strobe_phys, rtc_sp->strobe_size);
    if (rtc_sp->control_virt != NULL) {
	iounmap(rtc_sp->control_virt);
	rtc_sp->control_virt = NULL;
    }

    release_mem_region(rtc_sp->control_phys, rtc_sp->control_size);
    if (rtc_sp->encoder_virt != NULL) {
	iounmap(rtc_sp->encoder_virt);
	rtc_sp->encoder_virt = NULL;
    }

    release_mem_region(rtc_sp->encoder_phys, rtc_sp->encoder_size);
    if (rtc_sp->graphics_reg_virt != NULL) {
	iounmap(rtc_sp->graphics_reg_virt);
	rtc_sp->graphics_reg_virt = NULL;
    }

    release_mem_region(rtc_sp->graphics_reg_phys,
rtc_sp->graphics_reg_size);
    if (rtc_sp->cy545_trans_virt != NULL) {
	iounmap(rtc_sp->cy545_trans_virt);
	rtc_sp->cy545_trans_virt = NULL;
    }

    release_mem_region(rtc_sp->cy545_trans_phys,
rtc_sp->cy545_trans_size);
    if (rtc_sp->cy545_cr_virt != NULL) {
	iounmap(rtc_sp->cy545_cr_virt);
	rtc_sp->cy545_cr_virt = NULL;
    }

    release_mem_region(rtc_sp->cy545_cr_phys, rtc_sp->cy545_cr_size);
    if (rtc_sp->graphics_mem_virt != NULL) {
	iounmap(rtc_sp->graphics_mem_virt);
	rtc_sp->graphics_mem_virt = NULL;
    }

    release_mem_region(rtc_sp->graphics_mem_phys,
rtc_sp->graphics_mem_size);
    if (rtc_sp->shared_host_mem != NULL) {
	free_rtc_usr_shared(rtc_sp);
    }
}

static int 
rtc_map_one(RtcSoftDev *rtc_sp, u_long phys, u_long size, uint32_t
**virt, const char *what)       
{
    struct resource *res;

    if ((res = request_mem_region(phys,size,rtc_sp->devname)) == NULL) {
	debug_out(("rtc_map_one(%d): can't allocate %s at %010lx %#010lx
%s\n",
	    rtc_sp->dev_num, what, phys, size, rtc_sp->devname));

	return(-1);
    }

    else {
	*virt = ioremap_nocache(phys, size);
	if (!virt) {
	    debug_out(("rtc_map_one(%d): Error in ioremap\n",
rtc_sp->dev_num));

	    release_mem_region(phys, size);
	    return(-1);
	}
    }

    debug_out(("rtc_map_one(%d): Successful map %s: Phys %#lx\n",
	    rtc_sp->dev_num, what, phys));

    return(0);
}

static int
rtc_do_all_mappings(RtcSoftDev *rtc_sp)
{
    rtc_sp->snap_int_virt	= NULL;
    rtc_sp->digio_virt		= NULL;
    rtc_sp->strobe_virt		= NULL;
    rtc_sp->control_virt	= NULL;
    rtc_sp->encoder_virt	= NULL;
    rtc_sp->graphics_reg_virt	= NULL;
    rtc_sp->cy545_trans_virt	= NULL;
    rtc_sp->cy545_cr_virt	= NULL;
    rtc_sp->graphics_mem_virt	= NULL;

    /* Map Snap Interval */

    rtc_sp->snap_int_phys = rtc_sp->iobase + RTC_SNAP_INTERVAL_OFFSET;
    rtc_sp->snap_int_size = RTC_SNAP_INTERVAL_SIZE;		

    if (rtc_map_one(rtc_sp,
	    rtc_sp->snap_int_phys,
	    rtc_sp->snap_int_size,
	    &rtc_sp->snap_int_virt,
	    "Snap Interval") < 0)
    {
	return(-1);
    }

    /* Map Digital I/O */

    rtc_sp->digio_phys = rtc_sp->iobase + RTC_DIGIO_OFFSET;
    rtc_sp->digio_size = RTC_DIGIO_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->digio_phys,
	    rtc_sp->digio_size,
	    &rtc_sp->digio_virt,
	    "Digital I/O") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map Strobe Timer */

    rtc_sp->strobe_phys = rtc_sp->iobase + RTC_STROBE_TIMER_OFFSET;
    rtc_sp->strobe_size = RTC_STROBE_TIMER_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->strobe_phys,
	    rtc_sp->strobe_size,
	    &rtc_sp->strobe_virt,
	    "Strobe Timer") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map Control Register */

    rtc_sp->control_phys = rtc_sp->iobase + RTC_CONTROL_REG_OFFSET;
    rtc_sp->control_size = RTC_CONTROL_REG_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->control_phys,
	    rtc_sp->control_size,
	    &rtc_sp->control_virt,
	    "Control Reg") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map Encoder Counter */

    rtc_sp->encoder_phys = rtc_sp->iobase + RTC_ENCODER_CNT_OFFSET;
    rtc_sp->encoder_size = RTC_ENCODER_CNT_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->encoder_phys,
	    rtc_sp->encoder_size,
	    &rtc_sp->encoder_virt,
	    "Encoder Counter") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map Graphics Register */

    rtc_sp->graphics_reg_phys = rtc_sp->iobase +
RTC_GRAPHICS_REG_OFFSET;
    rtc_sp->graphics_reg_size = RTC_GRAPHICS_REG_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->graphics_reg_phys,
	    rtc_sp->graphics_reg_size,
	    &rtc_sp->graphics_reg_virt,
	    "Graphics Register") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map CY545 Trans Reg */

    rtc_sp->cy545_trans_phys = rtc_sp->iobase + RTC_CY545_TRANS_OFFSET;
    rtc_sp->cy545_trans_size = RTC_CY545_TRANS_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->cy545_trans_phys,
	    rtc_sp->cy545_trans_size,
	    &rtc_sp->cy545_trans_virt,
	    "CY545 Trans Reg") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map CY545 Control Reg */

    rtc_sp->cy545_cr_phys = rtc_sp->iobase + RTC_CY545_CONTROL_OFFSET;
    rtc_sp->cy545_cr_size = RTC_CY545_CONTROL_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->cy545_cr_phys,
	    rtc_sp->cy545_cr_size,
	    &rtc_sp->cy545_cr_virt,
	    "CY545 Control Reg") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    /* Map Graphics Memory */

    rtc_sp->graphics_mem_phys = rtc_sp->iobase +
RTC_GRAPHICS_MEM_OFFSET;
    rtc_sp->graphics_mem_size = RTC_GRAPHICS_MEM_SIZE;

    if (rtc_map_one(rtc_sp,
	    rtc_sp->graphics_mem_phys,
	    rtc_sp->graphics_mem_size,
	    &rtc_sp->graphics_mem_virt,
	    "Graphics Memory") < 0)
    {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    if (alloc_rtc_usr_shared(rtc_sp) < 0) {
	free_all_mappings(rtc_sp);
	return(-1);
    }

    return(0);
}

static int __initdata
rtc_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) {
    RtcSoftDev *rtc_sp;
    char revid = ' ';

    u8  rev_id = 0;
    u16 device_id;

    int result;
    int dev_num;
    int rtc_major;
    int intr_handler_req;

    if (pci_enable_device(pdev)) {
	return(-ENODEV);
    }

    /* stealing code from cciss.c - thanks compaq! */

    debug_out(("rtc_probe: RTC 0x%08x found @bus %d dev %d func %d\n",
	 pdev->device,
	 pdev->bus->number,
	 PCI_SLOT(pdev->devfn),
	 PCI_FUNC(pdev->devfn)));

    /* alloc our per-device data */
    dev_num = alloc_rtc_soft_state();

    if (dev_num < 0) {
	/* I've already printk'd error message */
	return(-ENOMEM);
    }

    result = 0;

    memset(RtcSoft[dev_num], 0, sizeof(RtcSoft[dev_num]));
    rtc_sp = RtcSoft[dev_num];

    sprintf(rtc_sp->devname, "mvp_rtc");

    spin_lock_init(&rtc_sp->mutex);
    rtc_sp->dev_num = dev_num;
    rtc_sp->pdev = pdev;

    sema_init(&rtc_sp->sem, 1);
    pci_set_drvdata(pdev,rtc_sp);	/* we'll need this in remove: */

    debug_out(("rtc_probe: device %d\n", dev_num));

#define REQUESTMEM
#ifdef REQUESTMEM
    /* 
     * map the card memory areas into kernel space
     * and store the address in our RtcDev info 
     */

    rtc_sp->iobase = pci_resource_start(pdev, 0);
    rtc_sp->iosize = pci_resource_len(pdev, 0);

    debug_out(("rtc_probe_module: base start %#010lx size %#010lx\n",
	    rtc_sp->iobase,
	    rtc_sp->iosize));

    if (rtc_do_all_mappings(rtc_sp) < 0) {
	debug_out(("rtc_probe: do_all_mappings failed\n"));

	free_rtc_soft_state(rtc_sp->dev_num);
	return(-ENODEV);
    }
#endif

#ifdef CONFIG_DEVFS_FS
    rtc_sp->rtc_devfs_dir = devfs_mk_dir(NULL, rtc_sp->devname, NULL);

    if (!rtc_sp->rtc_devfs_dir) {
	debug_out(("rtc_probe(%d): can't register devfs\n", dev_num));

	free_all_mappings(rtc_sp);
	free_rtc_soft_state(rtc_sp->dev_num);

	return(-EBUSY);
    }

    devfs_resister(rtc_sp->rtc_devfs_dir,
	    rtc_sp->devname,
	    DEVFS_FL_AUTO_DEVNUM,               /* autoallocate
major/minor */
	    0,                                  /* ignored because of
flag */
	    0,                                  /* ignored because of
flag */
	    S_IFCHR | S_IRUGO | S_IWUGO,        /* ??? */
	    &rtc_fops,
	    rtc_sp);

#else

    rtc_major = 0;
    result = register_chrdev(rtc_major, rtc_sp->devname, &rtc_fops);

    if (result < 0) {
	debug_out(("rtc_probe_module: can't get major %d\n",
rtc_major));

	free_all_mappings(rtc_sp);
	free_rtc_soft_state(rtc_sp->dev_num);

	return(-EBUSY);
    }

    if (rtc_major == 0) {
	rtc_major = result;
    }

    debug_out(("rtc_probe_module: got major %d\n", rtc_major));

#endif

    rtc_sp->rtc_major = rtc_major;

    pci_read_config_word(pdev, 2, &device_id);
    pci_read_config_byte(pdev, 8, &rev_id);

    if (rev_id > 0 && rev_id < 27) {
	rev_id += 0x40; 
	revid = rev_id;
    }

    if (!pdev->irq) {
	debug_out(("rtc_probe_module: can't get interrupt number\n"));

	free_all_mappings(rtc_sp);
	free_rtc_soft_state(rtc_sp->dev_num);
	return(-ENODEV);
    }

    rtc_sp->myint = pdev->irq;

    rtc_sp->irq_cnt = 0;
    intr_handler_req = request_irq(rtc_sp->myint,rtc_intr,
	    SA_SHIRQ,
	    rtc_sp->devname,
	    rtc_sp);

    if (intr_handler_req != 0) {
	debug_out(("rtc_probe_module: can't req interrupt handler\n"));

	free_all_mappings(rtc_sp);
	free_rtc_soft_state(rtc_sp->dev_num);
	return(-ENODEV);
    }

    debug_out(("MVP Real Time Controller Board A: %s%d, %X.%c, Int:
%d\n",
	    RTC_DEVICE, dev_num, device_id, revid, rtc_sp->myint));

    debug_out(("driver(%d) %s\n", dev_num, rtc_c));

    return(result);
}

static void __exitdata
rtc_remove(struct pci_dev *pci_dev)
{
    RtcSoftDev *rtc_sp = (RtcSoftDev *)pci_get_drvdata(pci_dev);

    if (rtc_sp == NULL) {
	debug_out(("rtc_remove: Error: Null RTC Data in remove\n"));
	return;
    }

    debug_out(("rtc_remove:\n"));

    unregister_chrdev(rtc_sp->rtc_major, rtc_sp->devname);

    free_irq(rtc_sp->myint, rtc_sp);
    rtc_sp->myint = 0;

    free_all_mappings(rtc_sp);
    free_rtc_soft_state(rtc_sp->dev_num);
}

static struct pci_device_id rtc_id_table[] __devinitdata = {
    { 0x8f73, 0xa1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
    { 0x8f73, 0xa2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 } };

/*
 * have _no idea_ why I'm calling this - find out!
 *
 *	from /usr/inluclude/linux/module.h
 * MODULE_DEVICE_TABLE exports information about devices
 * currently supported by this module.  A device type, such as PCI,
 * is a C-like identifier passed as the first arg to this macro.
 * The second macro arg is the variable containing the device
 * information being made public.
 *
 * The following is a list of known device types (arg 1),
 * and the C types which are to be passed as arg 2.
 * pci - struct pci_device_id - List of PCI ids supported by this module
 * isapnp - struct isapnp_device_id -
 * List of ISA PnP ids supported by this module
 * usb - struct usb_device_id - List of USB ids supported by this module
 *
 * still - ok so it exports it, who imports it and what do they
 * do with it?
 */

MODULE_DEVICE_TABLE(pci, rtc_id_table);

struct pci_driver rtc_driver = {
    name:		"rtc0",
    id_table:		rtc_id_table,
    probe:		rtc_probe,
    remove:		rtc_remove,
};

int __init
rtc_init_module(void)
{
    init_rtc_soft_state();
    return(pci_module_init(&rtc_driver));
}

void __exit
rtc_cleanup_module(void)
{
    pci_unregister_driver(&rtc_driver);
}

/*
 * RTC interrupt routine.  I could not get the outl() and inl() macros
to
 * work using the physical address.  So,using the virtual address of the
 * hardware seems to work.
 */

irqreturn_t
rtc_intr(int irq, void *dev_id, struct pt_regs *regs) {
    unsigned long creg_val = 0L;
    struct timeval tv;

    unsigned long flags;
    RtcSoftDev *rtc_sp = dev_id;

    if (rtc_sp == NULL)	{
	debug_out(("Rtc Intr: rtc_sp is NULL\n"));
	return(IRQ_NONE);
    }

    lock_rtc(rtc_sp,&flags,"rtc_intr");
    rtc_sp->irq_cnt++;
    creg_val = *rtc_sp->control_virt;

    if (!(creg_val & RCR_INTR)) {
	debug_out(("rtc_intr: SNAPINT not set\n"));

	unlock_rtc(rtc_sp, &flags, "rtc_intr Error");
	return(IRQ_NONE);
    }

    if (rtc_sp->shared_host_mem != NULL) {
    	rtc_sp->shared_host_mem->snap_addrs_loc++;
	do_gettimeofday(&tv);
	rtc_sp->shared_host_mem->ntimestamp = tv.tv_sec;

	debug_out(("rtc_intr: rtc_sp->shared_host_mem->snap_addrs_loc:
%d\n", 
	    rtc_sp->shared_host_mem->snap_addrs_loc));
    }
    else {
	debug_out(("rtc_intr: rtc_sp->shared_host_mem->snap_addrs_loc
NULL\n"));
    }

    *rtc_sp->control_virt |= RCR_INTRRESET;
    barrier();

    *rtc_sp->control_virt &= ~RCR_INTRRESET;
    unlock_rtc(rtc_sp,&flags,"rtc_intr");

    return(IRQ_HANDLED);
}

module_init(rtc_init_module);
module_exit(rtc_cleanup_module);


--->
/usr/src/redhat/BUILD/kernel-2.6.16.16/linux-2.16.16/dirvers/mvp/ibb.c

static const char *ibb_c = "$Id: ibb.c,v 1.5 2006/04/18 19:48:02 brian
Exp brian $(c) MVP ";

#include <asm/uaccess.h>
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/types.h>

#include "dev/ibb.h"
#include "ibbsoft.h"

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#ifndef CONFIG_PCI
#error "This driver REQUIRES PCI support!"
#endif

#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define
MODVERSIONS #endif

void ibb_rtc_wakeup(void);
irqreturn_t ibb_intr(int irq, void *dev_id, struct pt_regs *regs);

EXPORT_SYMBOL(ibb_rtc_wakeup);

/*
 * Split minors in two parts
 */
#define TYPE(dev)   (MINOR(dev) >> 4)  /* high nibble */
#define NUM(dev)    (MINOR(dev) & 0xf) /* low  nibble */

#define DEBUG

#ifdef DEBUG
#define debug_out(msg)		{ printk msg; }
#else
#define debug_out(msg)
#endif

/*
 * Place the call to START at the begining of the function and place the
call
 * to END where the function __should__ be returning at (not always at
the
 * end of the function, get it)!
 */

#define START
#define END

#if 0
#define START	{ debug_out(("IBB_START: %s\n", __func__)); }
#define END	{ debug_out(("IBB_FINISH: %s\n", __func__)); }
#endif

/*
 * array of devices
 */

static IbbSoftDev *IbbSoft[kMaxIbbs];

static const uint32_t kIoWaiting	= 0x04;
static const uint32_t MAG_FB_NUMBER	= 0xCE1E57E;
static const uint16_t kIbbWakeup	= 0x0fff;

/*
 * clamp the max frame buffer size to the lowest available memory size
*/ typedef struct ibb_ishared_attr {
    u_int32_t	frame_buffer_size;
    int32_t	dev_instance[kMaxIbbs];
} ibb_ishared_attr;

static ibb_ishared_attr ishared;

static void
lock_ibb(IbbSoftDev *ibb_sp, u_long *flags, const char *where) {
    START;

    debug_out(("lock_ibb(%d): %s:\n", ibb_sp->dev_num, where));
    spin_lock_irqsave(&ibb_sp->mutex, *flags);
    debug_out(("lock_ibb(%d): Done %s:\n", ibb_sp->dev_num, where));

    END;
}

static void
unlock_ibb(IbbSoftDev *ibb_sp, u_long *flags, const char *where) {
    START;
    debug_out(("unlock_ibb(%d): %s:\n", ibb_sp->dev_num, where));

    spin_unlock_irqrestore(&ibb_sp->mutex, *flags);

    debug_out(("unlock_ibb(%d): Done %s:\n", ibb_sp->dev_num, where));
    END;
}

static void
init_ibb_soft_state(void)
{
    int i;

    START;

    for (i = 0; i < kMaxIbbs; i++)
	IbbSoft[i] = NULL;

    END;
}

static int
alloc_ibb_soft_state(void)
{
    int i;

    START;

    for (i = 0; i < kMaxIbbs; i++) {
	if (IbbSoft[i] == NULL) {
	    IbbSoft[i] = kmalloc(sizeof(IbbSoftDev), GFP_KERNEL);

	    if (IbbSoft[i] == NULL) {
		debug_out(("alloc_ibb_soft_state: out of memory\n"));
		return(-1);
	    }

	    debug_out(("alloc_ibb_soft_state: return %d\n", i));

	    END;
	    return(i);
	}
    }

    return(-1);
}

/*
 * There may be a better way to do this!
 *
 * I need to make sure the data I initialized in ibb_probe()
 * for device "X"  is the same data I use in ibb_open().
 *
 * I could use the minor numbers, but I have to trust that
 * the 'load' script for the ibb device is written correctly,
 * since that's where minor numbers are assigned.
 *
 * So I'm using the major numbers.  It's a little slower, since
 * major numbers tend to be >200 I'm not just going to use
 * them as indexes into my array.  Instead I'm going though
 * all the devices looking for the matching major.
 *
 * My concern, frankly, is that no other drivers seem to be
 * using this method.  But it seems the only foolproof way
 * to keep the data with the device
 */

static int
find_ibb_soft_state(int ibb_major)
{
    int i;

    START;
    debug_out(("find_ibb_soft_state: major %d\n", ibb_major));

    for (i = 0; i < kMaxIbbs; i++) {
	if (IbbSoft[i] != NULL) {
	    if (ibb_major == IbbSoft[i]->ibb_major) {
		debug_out(("find_ibb_soft_state: return %d\n", i));

		END;
		return(i);
	    }
	}
    }

    debug_out(("Can't find matching soft_state %d!\n", ibb_major));
    return(-1);
}

static void
free_ibb_soft_state(int i)
{
    START;

    if (IbbSoft[i] == NULL) {
	debug_out(("IbbSoft[%d] is already free and null\n", i));
	return;
    }

    debug_out(("free_ibb_soft_state(%d):\n", IbbSoft[i]->dev_num));

    kfree(IbbSoft[i]);
    IbbSoft[i] = NULL;

    END;
    return;
}

ssize_t
ibb_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
    debug_out(("ibb_read: -EINVAL\n"));
    return(-EINVAL);
}

ssize_t
ibb_write(struct file *filp, const char *buf, size_t count, loff_t
*f_pos) {
    debug_out(("ibb_write: -EINVAL\n"));
    return(-EINVAL);
}

/*
 * IBBWAIT ioctl routine
 * wait for ushared->image_table_index to *exceed* value
 * passed in - (IBBWAIT,0) waits for snap 0 to be processed and
 * index to advance to 1
 */

static inline int
ibb_wait(IbbSoftDev *ibb_sp, u_long arg) {
    int dev_num = ibb_sp->dev_num;
    uint32_t table_index = (uint32_t) arg;

    u_long flags;
    int wq_ret = 0;

    START;

    if (ibb_sp->ushared == NULL) {
	return(EAGAIN);
    }

    if (ibb_sp->ushared->image_table_index > table_index) {
	debug_out(("ibb_ioctl(%d): IBBWAIT already got index %d\n",
	    dev_num, ibb_sp->ushared->image_table_index)); 

	return(0);
    }

    lock_ibb(ibb_sp, &flags, "IBBWAIT 0");

    ibb_sp->flags |= kIoWaiting;
    ibb_sp->wait_for = table_index;

    unlock_ibb(ibb_sp, &flags, "IBBWAIT 0");

    debug_out(("ibb_ioctl(%d): IBBWAIT wait for %u, %u\n",
	dev_num, ibb_sp->wait_for, ibb_sp->ushared->image_table_index)
);

    wq_ret = wait_event_interruptible(ibb_sp->wq, 
	(ibb_sp->ushared->image_table_index > table_index));

    debug_out(("ibb_ioctl(%d): IBBWAIT got index %d\n",
	dev_num,ibb_sp->wait_for));

    lock_ibb(ibb_sp, &flags, "IBBWAIT 1");
    ibb_sp->flags &= ~kIoWaiting;
    unlock_ibb(ibb_sp, &flags, "IBBWAIT 1");

    if (ibb_sp->wait_for == kIbbWakeup) {
	debug_out(("ibb_ioctl(%d): IBBWAIT got Wakeup\n", dev_num));
    }
    else if (ibb_sp->ushared->image_table_index > ibb_sp->wait_for) {
	debug_out(("ibb_ioctl(%d): IBBWAIT got index %d\n",
	    dev_num,ibb_sp->wait_for));
    }
    else {
	if(wq_ret != 0) {
	    debug_out(("ibb_ioctl(%d): IBBWAIT signal intr\n",
dev_num));
	} else {
	    debug_out(("ibb_ioctl(%d): IBBWAIT Weird cond.\n",
dev_num));
	}

	return(-1);	/* !! there's been a problem */
    }

    END;
    return(0);
}

int
ibb_ioctl(struct inode *inode, struct file *filp, u_int cmd, u_long arg)
{
    IbbSoftDev *ibb_sp = filp->private_data;

    int retval = 0;
    u_long flags;

    START;

    if (ibb_sp == NULL) {
	debug_out(("ibb_ioctl(%d): Soft Info Lost\n", ibb_sp->dev_num));
	return(-EFAULT);
    }

    switch (cmd) {
	case IBBWAIT:
	    debug_out(("ibb_ioctl(%d): cmd IBBWAIT arg %lu\n",
		ibb_sp->dev_num, arg));

	    retval = ibb_wait(ibb_sp, arg);
	    break;

	case IBBTST:
	    if (ibb_sp->image_table == NULL)
		return 0;

	    debug_out(("ibb_ioctl(%d): table 0 %x \n", 
		ibb_sp->dev_num,ibb_sp->image_table[0]) );

	    debug_out(("ibb_ioctl(%d): table 1 %x \n",
		ibb_sp->dev_num,ibb_sp->image_table[1]) );

	    break;

	case IBBWAKEUP:
	    debug_out(("ibb_ioctl(%d): cmd IBBWAKEUP\n",
ibb_sp->dev_num));

	    retval = 0;

	    if (ibb_sp->flags & kIoWaiting) {
		lock_ibb(ibb_sp, &flags, "IBBWAKEUP");
		ibb_sp->wait_for = kIbbWakeup;

		unlock_ibb(ibb_sp, &flags, "IBBWAKEUP");
		wake_up_interruptible(&ibb_sp->wq);
	    }

	    break;

	case IBBFBACOUNT:
	    debug_out(("ibb_ioctl(%d): cmd IBBFBACOUNT arg %lu\n",
		ibb_sp->dev_num, arg) );

	    lock_ibb(ibb_sp, &flags, "IBBFBACOUNT");
	    *(ibb_sp->fbac_virt) = (uint32_t) arg;
	    unlock_ibb(ibb_sp, &flags, "IBBFBACOUNT");

	    debug_out(("ibb_ioctl(%d): set fb count to %u\n",
		ibb_sp->dev_num,*(ibb_sp->fbac_virt)));

	    retval = 0;
	    break;

	case IBBFSIZE:
	    debug_out(("ibb_ioctl(%d): cmd IBBFSIZE arg %lu\n", 
		ibb_sp->dev_num,arg));

	    lock_ibb(ibb_sp, &flags, "IBBFSIZE");
	    *(ibb_sp->fsize_virt) = (uint32_t)arg;
	    unlock_ibb(ibb_sp, &flags, "IBBFSIZE");

	    debug_out(("ibb_ioctl(%d): set frame size to %u\n",
		ibb_sp->dev_num,*(ibb_sp->fsize_virt)));

	    break;

	case IBBSIZE:
	    debug_out(("ibb_ioctl(%d): cmd is IBBSIZE: %d\n", 
		ibb_sp->dev_num, ishared.frame_buffer_size));

	    retval = put_user(ishared.frame_buffer_size, (u_long *)
arg);
	    break;

	case IBBVERSION:
	    if (put_user(kIbbVersion, (u_long *) arg)) {
		debug_out(("ibb_ioctl(%d): can't copy ver info %d\n",
		    ibb_sp->dev_num,(int)kIbbVersion)) ;

		retval = -EFAULT;
	    }

	    debug_out(("ibb_ioctl(%d): Copied ver info %d\n",
		ibb_sp->dev_num, (int)kIbbVersion));
	
	    break;

	case IBBCLIBB_ID:
	    if (put_user(ibb_sp->clibb_id, (short *)arg)) {
		debug_out(("ibb_ioctl(%d): can't copy CLIBB ID %d\n",
		    ibb_sp->dev_num,ibb_sp->clibb_id)) ;

		retval = -EFAULT;
	    }

	    debug_out(("ibb_ioctl(%d): Copied CLIBB IDD %d\n",
		ibb_sp->dev_num,ibb_sp->clibb_id));
	
	    break;

	case IBBHEIGHTGO:
	    if (ibb_sp->clibb_id != kClibb_HSC) {
		debug_out(("ibb_ioctl(%d): ERROR: No Height Sensor\n",
		    ibb_sp->dev_num) );

		return(-EFAULT);
	    }

	    ibb_sp->height_inspection = 1;

	    debug_out(("ibb_ioctl(%d): Start Height Inspection %d\n",
		ibb_sp->dev_num,ibb_sp->height_inspection));
	
	    break;

	case IBBHEIGHTSTOP:
	    ibb_sp->height_inspection = 0;

	    debug_out(("ibb_ioctl(%d): Stop Height Inspection %d\n",
		ibb_sp->dev_num,ibb_sp->height_inspection));
	
	    break;

	default:
	    debug_out(("ibb_ioctl(%d): unknown case: %d\n", 
		ibb_sp->dev_num, cmd) );

	    return(-ENOTTY);
	    break;
    }

    END;
    return(retval);
}

int
ibb_open(struct inode *inode, struct file *filep) {
    int dev_num;
    IbbSoftDev *ibb_sp;

    int major = MAJOR(inode->i_rdev);
    int minor = MINOR(inode->i_rdev);

    START;

    debug_out(("ibb_open: major %d minor %d\n", major, minor));
    dev_num = find_ibb_soft_state(major);

    if (dev_num < 0) {
	debug_out(("ibb_open: dev_num %d failed\n", dev_num));
	return(-1);
    }

    ibb_sp = IbbSoft[dev_num];
    filep->private_data = ibb_sp;

    debug_out(("ibb_open(%d): opened by %s pid %d PAGE_SIZE %#010lx\n",
    	dev_num,current->comm, current->pid, PAGE_SIZE));

    END;
    return(0);
}

int
ibb_close(struct inode *inode, struct file *filep) {
    IbbSoftDev *ibb_sp = filep->private_data;

    START;
    debug_out(("ibb_close(%d): called\n", ibb_sp->dev_num));

    END;
    return(0);
}

/*
 * According to what I was told on the mailing lists, ClearPageReserved
is
 * now depricated and shouldn't be needed but we can leave it for now
for
 * backwards compatability (until when???) but also that you should
never,
 * ever access _count (in atomic_set(&page->_count) directly so it's
commented
 * out becuase I don't really know why it's there????
 *
 * BDM - 04/18/2006
 */

static void
free_ibb_usr_shared(IbbSoftDev *ibb_sp)
{
    struct page *page;

    u_long virt_addr;
    u_long ushared_addr = (u_long)ibb_sp->ushared;

    START;

    for (virt_addr = ushared_addr; 
	    virt_addr < ushared_addr + PAGE_ALIGN(IBB_SHARED_SIZE);
	    virt_addr += PAGE_SIZE)
    {
    	page = virt_to_page(virt_addr);
	ClearPageReserved(page);

	// atomic_set(&page->_count, 1);
	vfree((void *)virt_addr);
    }

    if (ibb_sp->ushared)
	ibb_sp->ushared = NULL;

    END;
}

static int
alloc_ibb_usr_shared(IbbSoftDev *ibb_sp) {
    u_long virt_addr;
    u_long ushared_addr;

    int order = 0;

    /* 
     * From Linux Device Drivers - memory that is going to
     * be mmaped must be PAGE_SIZE grained.  Since we do mmap
     * ushared to user space, we need to allocated it in
     * PAGE_SIZE chunks.
     */

    int size = PAGE_ALIGN(IBB_SHARED_SIZE);

    START;

    debug_out(("ibb::size is %d\n", size));
    debug_out(("ibb::order is %d\n", order));

    do {
	debug_out(("ibb::size is %d\n", size));
	debug_out(("ibb::order is %d\n", order));

    	order++;
    } while (size > (PAGE_SIZE * (1 << order)));

    ibb_sp->ushared = (IbbUserShared *) __get_free_pages(GFP_KERNEL,
order);
    // ibb_sp->ushared = (IbbUserShared *) vmalloc(4096 * 1024);
    // ibb_sp->ushared = (IbbUserShared *) vmalloc(size);

    if (ibb_sp->ushared == NULL) {
	debug_out(("alloc_ibb_usr_shared(%d): no memory.\n",
ibb_sp->dev_num));
	return(-1);
    }

    ushared_addr = (u_long) ibb_sp->ushared;

    /* reserve all pages to make them remapable */

    for (virt_addr = ushared_addr;
	    virt_addr < ushared_addr + size;
	    virt_addr += PAGE_SIZE)
    {
	SetPageReserved(virt_to_page(virt_addr));
    }

    ibb_sp->ushared->badsnap = 0;
    ibb_sp->ushared->image_table_index = 0;

    END;
    return(0);
}

/*
 * According to what I was told on the mailing lists, ClearPageReserved
is
 * now depricated and shouldn't be needed but we can leave it for now
for
 * backwards compatability (until when???) but also that you should
never,
 * ever access _count (in atomic_set(&page->_count) directly so it's
commented
 * out becuase I don't really know why it's there????
 *
 * BDM - 04/18/2006
 */

static void
free_ibb_image_table_mem(IbbSoftDev *ibb_sp) {
    uint32_t *virt_addr;
    struct page *page;

    START;

    debug_out(("free_ibb_image_table_mem(%d): Free size %d.\n",
	ibb_sp->dev_num, ibb_sp->image_table_size));

    /* unreserve all pages */

    for (virt_addr = ibb_sp->image_table; 
	   virt_addr < ibb_sp->image_table + ibb_sp->image_table_size;
	   virt_addr += PAGE_SIZE)
    {
    	page = virt_to_page(virt_addr);
	ClearPageReserved(page);

	// atomic_set(&page->_count, 1);
	free_page((u_long)virt_addr);
    }

    if (ibb_sp->image_table) {
	ibb_sp->image_table = NULL;
    }

    ibb_sp->image_table_size = 0;
    debug_out(("static void free_ibb_image_table_mem - DONE!\n"));

    END;
    return;
}

static int
alloc_ibb_image_table_mem(IbbSoftDev *ibb_sp, int size) {
    int order = 0;
    uint32_t *virt_addr;

    u_int table_size = PAGE_ALIGN(size);

    START;

    debug_out(("alloc_ibb_image_table_mem(%d): Alloc size %d.\n",
	ibb_sp->dev_num,table_size));

    /* 
     * get a memory area with kmalloc and aligned it to a page. This
area
     * will be physically contigous
     */

    while (size > (PAGE_SIZE * (1 << order))) {
    	order++;
    }

    ibb_sp->image_table = (uint32_t *) __get_free_pages(GFP_KERNEL,
order);
    // ibb_sp->ushared = (IbbUserShared *) vmalloc(4096 * 1024);
    // ibb_sp->image_table = vmalloc(size);

    if (ibb_sp->image_table == NULL) {
	debug_out(("alloc_ibb_image_table_mem(%d): out of memory.\n",
	    ibb_sp->dev_num));

	ibb_sp->image_table_size = 0;
	return(-1);
    }

    /* reserve all pages to make them remapable */

    for (virt_addr = ibb_sp->image_table; 
	    virt_addr < ibb_sp->image_table + table_size; 
	    virt_addr += PAGE_SIZE)
    {
	SetPageReserved(virt_to_page(virt_addr));
    }

    ibb_sp->image_table_size = table_size;
    debug_out(("static int alloc_ibb_image_table_mem - DONE!\n"));

    END;
    return(0);
}

static int 
ibb_map_one(IbbSoftDev *ibb_sp, u_long phys, u_long size, uint32_t
**virt, const char *what)       
{
    struct resource *res;

    START;

    if ((res = request_mem_region(phys, size, ibb_sp->devname)) == NULL)
{
	debug_out(( "ibb_map_one(%d): can't allocate %s at %010lx
%#010lx %s\n",
	    ibb_sp->dev_num, what, phys, size, ibb_sp->devname));

	return(-1);
    }
    else {
	*virt = ioremap_nocache(phys, size);

	if (!virt) {
	    debug_out(("ibb_map_one(%d): Error in ioremap\n",
ibb_sp->dev_num));

	    release_mem_region(phys, size);
	    return(-1);
	}
    }

    debug_out(("ibb_map_one(%d): Successful map %s\n",
ibb_sp->dev_num,what));

    END;
    return(0);
}

static void
free_all_mappings(IbbSoftDev *ibb_sp)
{
    START;

    if (ibb_sp->creg_virt != NULL) {
	iounmap(ibb_sp->creg_virt);
	ibb_sp->creg_virt = NULL;
    }

    /* we can call release_mem_region() without checking anything -
     * if the region hasn't been requested, the function will
     * just exit with an error message.
     * (unlike iounmap())
     */

    release_mem_region(ibb_sp->creg_phys, ibb_sp->creg_size);
    if (ibb_sp->height_virt != NULL) {
	iounmap(ibb_sp->height_virt);
	ibb_sp->height_virt = NULL;
    }

    release_mem_region(ibb_sp->height_phys, ibb_sp->height_size);
    if (ibb_sp->csram_virt != NULL) {
	iounmap(ibb_sp->csram_virt);
	ibb_sp->csram_virt = NULL;
    }

    release_mem_region(ibb_sp->csram_phys, ibb_sp->csram_size);
    if (ibb_sp->rsram_virt != NULL) {
	iounmap(ibb_sp->rsram_virt);
	ibb_sp->rsram_virt = NULL;
    }

    release_mem_region(ibb_sp->rsram_phys, ibb_sp->rsram_size);
    if (ibb_sp->fbac_virt != NULL) {
	iounmap(ibb_sp->fbac_virt);
	ibb_sp->fbac_virt = NULL;
    }

    release_mem_region(ibb_sp->fbac_phys, ibb_sp->fbac_size);
    if (ibb_sp->camdelay_virt != NULL) {
	iounmap(ibb_sp->camdelay_virt);
	ibb_sp->camdelay_virt = NULL;
    }

    release_mem_region(ibb_sp->camdelay_phys, ibb_sp->camdelay_size);
    if (ibb_sp->fsize_virt != NULL) {
	iounmap(ibb_sp->fsize_virt);
	ibb_sp->fsize_virt = NULL;
    }

    release_mem_region(ibb_sp->fsize_phys, ibb_sp->fsize_size);
    if (ibb_sp->extime_virt != NULL) {
	iounmap(ibb_sp->extime_virt);
	ibb_sp->extime_virt = NULL;
    }

    release_mem_region(ibb_sp->extime_phys, ibb_sp->extime_size);
    if (ibb_sp->plsram_virt != NULL) {
	iounmap(ibb_sp->plsram_virt);
	ibb_sp->plsram_virt = NULL;
    }

    release_mem_region(ibb_sp->plsram_phys, ibb_sp->plsram_size);
    if (ibb_sp->fb0_virt != NULL) {
	iounmap(ibb_sp->fb0_virt);
	ibb_sp->fb0_virt = NULL;
    }

    release_mem_region(ibb_sp->fb0_phys, ibb_sp->fb0_size);
    if (ibb_sp->fb1_virt != NULL) {
	iounmap(ibb_sp->fb1_virt);
	ibb_sp->fb1_virt = NULL;
    }

    release_mem_region(ibb_sp->fb1_phys, ibb_sp->fb1_size);
    if (ibb_sp->image_table != NULL) {
	free_ibb_image_table_mem(ibb_sp);
    }

    if (ibb_sp->ushared != NULL) {
	free_ibb_usr_shared(ibb_sp);
    }

    END;
    return;
}

static int
ibb_map_frame_buffer(IbbSoftDev *ibb_sp, u_long phys, ulong
*size,uint32_t **virt, const char *what) {
    char whatsize[100];
    uint32_t *check_addr;

    long check;

    START;

    sprintf(whatsize, "%s 64", what);
    *size = IBB_FB_64_MG;

    if (ibb_map_one(ibb_sp, phys, *size, virt, whatsize) < 0) {
	return(-1);
    }

    check = MAG_FB_NUMBER;
    check_addr = *virt;

    writel(check, check_addr);

    debug_out(("ibb_map_frame_buffer(%d): %s put %lX at addr %p\n",
	ibb_sp->dev_num, whatsize, check, check_addr));

    check = readl(check_addr);

    debug_out(("ibb_map_frame_buffer(%d): %s read %lX at addr %p\n",
	ibb_sp->dev_num, whatsize, check, check_addr));

    check_addr = (*virt) + (IBB_FB_32_MG / 4);
    check = readl(check_addr);

    debug_out(("ibb_map_frame_buffer(%d): %s read %lX at addr %p\n",
	ibb_sp->dev_num, whatsize, check, check_addr));

    if (check == MAG_FB_NUMBER) {
	/* we only have 32 MB, but we've mapped 64 - try again */

	iounmap(*virt);
	(*virt) = NULL;
	release_mem_region(phys, *size);

	sprintf(whatsize, "%s 32", what);
	*size = IBB_FB_32_MG;

	if (ibb_map_one(ibb_sp, phys, *size, virt, whatsize) < 0) {
	    return(-1);
	}

	ishared.frame_buffer_size = IBB_FB_32_MG;
    }

    END;
    return(0);
}

static int
ibb_do_all_mappings(IbbSoftDev *ibb_sp)
{
    START;

    /* 
     * Initialize here so we can call free_all_mappings without
     * freeing unallocated mem
     */

    ibb_sp->creg_virt		= NULL;
    ibb_sp->height_virt		= NULL;
    ibb_sp->csram_virt		= NULL;
    ibb_sp->rsram_virt		= NULL;
    ibb_sp->fbac_virt		= NULL;
    ibb_sp->camdelay_virt	= NULL;
    ibb_sp->fsize_virt		= NULL;
    ibb_sp->extime_virt		= NULL;
    ibb_sp->plsram_virt		= NULL;
    ibb_sp->fb0_virt		= NULL;
    ibb_sp->fb1_virt		= NULL;
    ibb_sp->image_table		= NULL;
    ibb_sp->image_table_size	= 0;

    /* Map Control Register */

    ibb_sp->creg_phys = ibb_sp->iobase + IBB_CONTROL_OFF;
    ibb_sp->creg_size = IBB_CONTROL_SIZE;		

    if (ibb_map_one(ibb_sp,
	    ibb_sp->creg_phys,
	    ibb_sp->creg_size,
	    &ibb_sp->creg_virt,
	    "Control Register") < 0)
    {
	return(-1);
    }

    /* Map Height Sensor Register */

    ibb_sp->height_phys = ibb_sp->iobase + IBB_HEIGHT_OFF;
    ibb_sp->height_size = IBB_HEIGHT_SIZE;		

    if (ibb_map_one(ibb_sp,
	    ibb_sp->height_phys,
	    ibb_sp->height_size,
	    &ibb_sp->height_virt,
	    "Height Sensor") < 0)
    {
	return(-1);
    }

    /* Map Col Sram */

    ibb_sp->csram_phys = ibb_sp->iobase + IBB_CSRAM_OFF;
    ibb_sp->csram_size = IBB_CSRAM_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->csram_phys,
	    ibb_sp->csram_size,
	    &ibb_sp->csram_virt,
	    "Col Sram") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* Map Row Sram */

    ibb_sp->rsram_phys = ibb_sp->iobase + IBB_RSRAM_OFF;
    ibb_sp->rsram_size = IBB_RSRAM_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->rsram_phys,
	    ibb_sp->rsram_size,
	    &ibb_sp->rsram_virt,
	    "Row Sram") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map FB Address Counter */

    ibb_sp->fbac_phys = ibb_sp->iobase + IBB_FBACOUNT_OFF;
    ibb_sp->fbac_size = IBB_FBACOUNT_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->fbac_phys,
	    ibb_sp->fbac_size,
	    &ibb_sp->fbac_virt,
	    "FB Addr Count") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map Camera Delay Register */

    ibb_sp->camdelay_phys = ibb_sp->iobase + IBB_CAMDELAY_OFF;
    ibb_sp->camdelay_size = IBB_CAMDELAY_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->camdelay_phys,
	    ibb_sp->camdelay_size,
	    &ibb_sp->camdelay_virt,
	    "Cameral Delay Reg") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map Frame Size Register */

    ibb_sp->fsize_phys = ibb_sp->iobase + IBB_FSIZE_OFF;
    ibb_sp->fsize_size = IBB_FSIZE_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->fsize_phys,
	    ibb_sp->fsize_size,
	    &ibb_sp->fsize_virt,
	    "Frame Size Reg") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map Exposure Time Register */

    ibb_sp->extime_phys = ibb_sp->iobase + IBB_EXTIME_OFF;
    ibb_sp->extime_size = IBB_EXTIME_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->extime_phys,
	    ibb_sp->extime_size,
	    &ibb_sp->extime_virt,
	    "Exposure Time Reg") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map Pixel LUT Sram */

    ibb_sp->plsram_phys = ibb_sp->iobase + IBB_PLSRAM_OFF;
    ibb_sp->plsram_size = IBB_PLSRAM_SIZE;

    if (ibb_map_one(ibb_sp,
	    ibb_sp->plsram_phys,
	    ibb_sp->plsram_size,
	    &ibb_sp->plsram_virt,
	    "Pixel LUT Sram") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    /* map Frame Buffers - now it gets a little trickier */

    ibb_sp->fb0_phys = ibb_sp->iobase + IBB_FB0_OFF;
    ibb_sp->fb0_size = 0;

    if (ibb_map_frame_buffer(ibb_sp,
	    ibb_sp->fb0_phys,
	    &ibb_sp->fb0_size,
	    &ibb_sp->fb0_virt,
	    "Frame Buffer 0") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    debug_out(("ibb_do_all_mappings(%d): fb0 Mapped Size %lx\n",
	ibb_sp->dev_num,ibb_sp->fb0_size));

    ibb_sp->fb1_phys = ibb_sp->iobase + IBB_FB1_OFF;
    ibb_sp->fb1_size = 0;

    if (ibb_map_frame_buffer(ibb_sp,
	    ibb_sp->fb1_phys,
	    &ibb_sp->fb1_size,
	    &ibb_sp->fb1_virt,
	    "Frame Buffer 1") < 0)
    {
	free_all_mappings(ibb_sp);
	return(-1);
    }

    debug_out(("ibb_do_all_mappings(%d): fb1 Mapped Size %lx\n",
	ibb_sp->dev_num,ibb_sp->fb1_size));

    if (alloc_ibb_usr_shared(ibb_sp) < 0) {
	free_all_mappings(ibb_sp);
        return(-1);
    }

    debug_out(("ibb_do_all_mappings(%d): IbbUserShared %lx\n",
	ibb_sp->dev_num, (long)IBB_SHARED_SIZE));

    END;
    return(0);
}

int
ibb_mmap(struct file *filep, struct vm_area_struct *vma) {
    IbbSoftDev *ibb_sp = filep->private_data;

    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - vma->vm_start;
    unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT);
    unsigned long page = (ibb_sp->iobase + offset) >> PAGE_SHIFT;

    START;

    if (offset > __pa(high_memory) || (filep->f_flags & O_SYNC)) {
	vma->vm_flags |= VM_IO;
    }

    vma->vm_flags |= VM_RESERVED;

    debug_out((
	"mmap(%d): st %#010lx off %#010lx(%#010lx) sz %#010lx (end
%#010lx)\n",
	ibb_sp->dev_num, vma->vm_start, ibb_sp->iobase + offset,
	offset, (vma->vm_end - vma->vm_start), vma->vm_end));

    debug_out(("ibb_mmap(%d): opened by %s pid %d\n",
	ibb_sp->dev_num, current->comm, current->pid));

    if (offset == IBB_IMAGE_ADDR) {
	debug_out(("IBB_IMAGE_ADDR\n"));

	if (ibb_sp->image_table != NULL && size >
ibb_sp->image_table_size) {
	    debug_out(("ibb_mmap(%d): Free Image Table\n",
ibb_sp->dev_num));
	    free_ibb_image_table_mem(ibb_sp);
	}

	if (ibb_sp->image_table == NULL) {
	    debug_out(("ibb_mmap(%d): Alloc New Image Table\n",
		ibb_sp->dev_num));

	    alloc_ibb_image_table_mem(ibb_sp, (vma->vm_end -
vma->vm_start));
	}

	if (ibb_sp->image_table != NULL && size <=
ibb_sp->image_table_size) {
	    while (size > PAGE_SIZE) {
		if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		    return(-EAGAIN);
		}

		start += PAGE_SIZE;

		if (size > PAGE_SIZE) {
		    size -= PAGE_SIZE;
		} else {
		    size = 0;
		}
	    }
	}

	debug_out(("IBB_IMAGE_ADDR - DONE!\n"));
    }

    else if (offset == IBB_SHARED_ADDR) {
	debug_out(("IBB_SHARED_ADDR\n"));

	if (ibb_sp->ushared != NULL && size <=
PAGE_ALIGN(IBB_SHARED_SIZE)) {
	    while (size > PAGE_SIZE) {
		if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		    return(-EAGAIN);
		}

		start += PAGE_SIZE;

		if (size > PAGE_SIZE) {
		    size -= PAGE_SIZE;
		} else {
		    size = 0;
		}
	    }

	    debug_out(("ibb_mmap(%d): \
		ushared remap: ibb_sp->ushared: %lx vma->vm_start:
%lx\n",
		ibb_sp->dev_num,
		(u_long)ibb_sp->ushared,
		(u_long)vma->vm_start) );
	} else {
	    debug_out(("ibb_mmap(%d): ushared mmap failed\n",
ibb_sp->dev_num));
	    return(-EAGAIN);
	}

	debug_out(("IBB_SHARED_ADDR - DONE!\n"));
    }

    else if (offset == IBB_CONTROL_OFF && size == PAGE_SIZE) {
	debug_out(("IBB_CONTROL_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_CONTROL_OFF - DONE!\n"));
    }

    else if (offset == IBB_CSRAM_OFF && size == IBB_CSRAM_SIZE) {
	debug_out(("IBB_CSRAM_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_CSRAM_OFF - DONE!\n"));
    }

    else if (offset == IBB_RSRAM_OFF && size == IBB_RSRAM_SIZE) {
	debug_out(("IBB_RSRAM_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_RSRAM_OFF - DONE!\n"));
    }

    else if (offset == IBB_FBACOUNT_OFF && size == PAGE_SIZE) {
	debug_out(("IBB_FBACOUNT_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_FBACOUNT_OFF - DONE!\n"));
    }

    else if (offset == IBB_CAMDELAY_OFF && size == PAGE_SIZE) {
	debug_out(("IBB_CAMDELAY_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_CAMDELAY_OFF - DONE!\n"));
    }

    else if (offset == IBB_FSIZE_OFF && size == PAGE_SIZE) {
	debug_out(("IBB_FSIZE_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_FSIZE_OFF - DONE!\n"));
    }

    else if (offset == IBB_EXTIME_OFF && size == PAGE_SIZE) {
	debug_out(("IBB_EXTIME_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_EXTIME_OFF - DONE!\n"));
    }

    else if (offset == IBB_PLSRAM_OFF && size == IBB_PLSRAM_SIZE) {
	debug_out(("IBB_PLSRAM_OFF\n"));

	debug_out(("ibb_mmap(%d): PLUT Sram %lx %lx\n",
	     ibb_sp->dev_num, (long)offset, size));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_PLSRAM_OFF - DONE!\n"));
    }

    else if (offset == IBB_FB0_OFF
	&& (size == IBB_FB_32_MG
	|| size == IBB_FB_64_MG))
    {
	debug_out(("IBB_FB0_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_FB0_OFF - DONE!\n"));
    }

    else if (offset == IBB_FB1_OFF
	&& (size == IBB_FB_32_MG
	|| size == IBB_FB_64_MG))
    {
	debug_out(("IBB_FB1_OFF\n"));

	while (size > PAGE_SIZE) {
	    if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
		return(-EAGAIN);
	    }

	    start += PAGE_SIZE;

	    if (size > PAGE_SIZE) {
		size -= PAGE_SIZE;
	    } else {
		size = 0;
	    }
	}

	debug_out(("IBB_FB1_OFF - DONE!\n"));
    }

    else {
	debug_out(("IBB_???_OFFSET --- WE'RE BROKEN!!!\n"));
	return(-EAGAIN);
    }

    END;
    return(0);
}

struct file_operations ibb_fops = {
    read:	ibb_read,
    write:	ibb_write,
    ioctl:	ibb_ioctl,
    mmap:	ibb_mmap,
    open:	ibb_open,
    release:	ibb_close,
};

static int __initdata
ibb_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) {
    IbbSoftDev *ibb_sp;	

    int i = 0;
    int dev_num;
    int ibb_major;
    int result;
    int res;

    u8 rev_id = 0;
    u16 device_id;
    uint16_t subsystem_id = 0;

    char revid = ' ';

    START;

    if (pci_enable_device(pdev))
	return(-ENODEV);

    result = 0;

    debug_out((
	"ibb_probe: IBB Device 0x%08x has been found @bus %d dev %d func
%d\n",
	 pdev->device,
	 pdev->bus->number,
	 PCI_SLOT(pdev->devfn),
	 PCI_FUNC(pdev->devfn)));

    /* alloc our per-device data */

    dev_num = alloc_ibb_soft_state();

    if (dev_num < 0)
	return(-ENOMEM);

    /* initialize data */

    memset(IbbSoft[dev_num], 0, sizeof(IbbSoft[dev_num]));
    ibb_sp = IbbSoft[dev_num];

    sprintf(ibb_sp->devname, "ibb%d", dev_num);

    spin_lock_init(&ibb_sp->mutex);

    ibb_sp->dev_num = dev_num;
    ibb_sp->pdev = pdev;
    ibb_sp->height_inspection = 0;

    sema_init(&ibb_sp->sem, 1);
    pci_set_drvdata(pdev, ibb_sp);	/* we'll need this in remove: */

    debug_out(("ibb_probe: device %d\n", dev_num));

#define REQUESTMEM
#ifdef REQUESTMEM

    for (i = 0; i < kMaxIbbs; i++) {
    	ishared.dev_instance[i] = -1;
    }

    /* start with the max size */
    ishared.frame_buffer_size = IBB_FB_64_MG;

    /* 
     * map the card memory areas into kernel space
     * and store the address in our IbbDev info 
     */

    ibb_sp->iobase = pci_resource_start(pdev, 0);
    ibb_sp->iosize = pci_resource_len(pdev, 0);

    if (ibb_do_all_mappings(ibb_sp) < 0) {
	free_ibb_soft_state(ibb_sp->dev_num);
	return(-ENODEV);
    }

#endif

    ibb_major = 0;
    result = register_chrdev(ibb_major, ibb_sp->devname, &ibb_fops);

    if (result < 0) {
	debug_out(("ibb_probe(%d): can't get register driver\n",
dev_num));

	free_all_mappings(ibb_sp);
	free_ibb_soft_state(ibb_sp->dev_num);

	return(-EBUSY);
    }

    if (ibb_major == 0) {
	ibb_major = result;	/* dynamic */
    }

    debug_out(("ibb_probe(%d): got major %d\n",dev_num,ibb_major));

    ibb_sp->ibb_major = ibb_major;

    pci_read_config_word(pdev, 2, &device_id);
    pci_read_config_byte(pdev, 8, &rev_id);
    pci_read_config_word(pdev, 46, &subsystem_id);

    ibb_sp->clibb_id = subsystem_id;

    if (rev_id > 0 && rev_id < 27) {
	rev_id += 0x40;         /* translate to ascii (A = 1, B = 2,
etc) */
	revid = rev_id;
    }

    if (!pdev->irq) {
	debug_out(("ibb_probe_module(%d): can't get int number\n",
dev_num));

	free_all_mappings(ibb_sp);
	free_ibb_soft_state(ibb_sp->dev_num);

	return(-ENODEV);
    }

    ibb_sp->myint = pdev->irq;
    res = request_irq(ibb_sp->myint,
	    ibb_intr,
	    SA_SHIRQ,ibb_sp->devname,
	    ibb_sp);

    if (res != 0) {
	debug_out(("ibb_open(%d): irq request %d failed\n", dev_num,
res));
    	return(-1);
    }

    init_waitqueue_head(&ibb_sp->wq);

    if (ibb_sp->clibb_id == kIbbId) {
	debug_out(("MVP Image Buffer Board: ibb%d, %X.%c, Int: %d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    else if (ibb_sp->clibb_id == kClibbSingle) {
	debug_out(("MVP Camera Link Single IBB: ibb%d, %X.%c, Int:
%d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    else if (ibb_sp->clibb_id == kClibbDualRow) {
	debug_out(("MVP Camera Link DualRow IBB: ibb%d, %X.%c, Int:
%d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    else if (ibb_sp->clibb_id == kClibbDualCol) {
	debug_out(("MVP CL DualCol IBB ibb%d, %X.%c, Int: %d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    else if (ibb_sp->clibb_id == kClibb_HSC) {
	debug_out(("MVP HSC Camera Link IBB: ibb%d, %X.%c, Int: %d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    else {
	debug_out(("MVP Unknown IBB: ibb%d, %X.%c, Int: %d\n",
		dev_num,
		device_id,
		revid,
		ibb_sp->myint));
    }

    /* store device id */
    debug_out(("MVP driver(%d) %s\n", dev_num, ibb_c));

    END;
    return(result);
}

static void __exitdata
ibb_remove(struct pci_dev *pdev)
{
    IbbSoftDev *ibb_sp = (IbbSoftDev *)pci_get_drvdata(pdev);

    START;

    if (ibb_sp == NULL) {
	debug_out(("ibb_remove: Error: Null IBB Data in remove\n"));
	return;
    }

    debug_out(("ibb_remove(%d):\n", ibb_sp->dev_num));

    debug_out(("ibb_remove(%d): unregister drv %s\n",
	    ibb_sp->dev_num,
	    ibb_sp->devname));

    if (ibb_sp) {
	free_irq(ibb_sp->myint, (void *)ibb_sp);

	debug_out(("ibb_remove(%d): free_irq myint%d\n",
		ibb_sp->dev_num,
		ibb_sp->myint));

	ibb_sp->myint = 0;
    }
    
    unregister_chrdev(ibb_sp->ibb_major, ibb_sp->devname);

    debug_out(("ibb_remove(%d): release memory\n", ibb_sp->dev_num));

    free_all_mappings(ibb_sp);
    free_ibb_soft_state(ibb_sp->dev_num);

    END;
}

static struct pci_device_id ibb_id_table[] __devinitdata = {
    { 0x8f73, 0xb1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
    { 0x8f73, 0xb2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
    { 0x8f73, 0xb3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
    { 0x8f73, 0xcb1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
    { 0x8f73, 0xcb2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 } };

/*
 * have _no idea_ why I'm calling this - find out!
 *
 *	from /usr/inluclude/linux/module.h
 * MODULE_DEVICE_TABLE exports information about devices
 * currently supported by this module.  A device type, such as PCI,
 * is a C-like identifier passed as the first arg to this macro.
 * The second macro arg is the variable containing the device
 * information being made public.
 *
 * The following is a list of known device types (arg 1),
 * and the C types which are to be passed as arg 2.
 * pci - struct pci_device_id - List of PCI ids supported by this module
 * isapnp - struct isapnp_device_id -
 * List of ISA PnP ids supported by this module
 * usb - struct usb_device_id - List of USB ids supported by this module
 *
 * still - ok so it exports it, who imports it and what do they
 * do with it?
 */

MODULE_DEVICE_TABLE(pci, ibb_id_table);

struct pci_driver ibb_driver = {
    name:		"ibb",
    id_table:		ibb_id_table,
    probe:		ibb_probe,
    remove:		ibb_remove,
};

int __init
ibb_init_module(void)
{
    START;
    init_ibb_soft_state();

    END;
    return(pci_module_init(&ibb_driver));
}

void __exit
ibb_cleanup_module(void)
{
    START;
    pci_unregister_driver(&ibb_driver);

    END;
}

static inline void
set_next_fb(uint32_t *control_regp, uint32_t next_snap, int instance,
int temp_debug) {
    uint32_t next_fb = (next_snap & IAT_FB_MASK) >> IAT_FB_SHIFT;

    START;

    if (next_fb == 0) {
	*(control_regp) = *(control_regp) | ICR_FB0_ENABL;
	*(control_regp) = *(control_regp) & ~ICR_FB1_ENABL;
    }
    else if (next_fb == 1) {
	*(control_regp) = *(control_regp) | ICR_FB1_ENABL;
	*(control_regp) = *(control_regp) & ~ICR_FB0_ENABL;
    }

    debug_out(("ibb_intr(%d): set fb %d %x\n",
	    instance,
	    next_fb,
	    *(control_regp)));

    END;
}

static inline void
set_next_camera(uint32_t *control_regp, uint32_t next_snap, int
instance, int temp_debug) {
    uint32_t next_camera;

    START;

    /* first, clear the previous camera settings */
    *(control_regp) &= ICR_CLEARCAM;

    next_camera = (next_snap & IAT_CAMERA_MASK) >> IAT_CAMERA_SHIFT;

    if (next_camera < 0 || next_camera > 7) {
	return;
    }

    *(control_regp) |= (next_camera << ICR_CAMERA_SHIFT);

    debug_out(("ibb_intr(%d): set camera %d reg %x\n",
	    instance,
	    next_camera,
	    *(control_regp)) );

    END;
}

static inline void
set_next_address(IbbSoftDev *ibb_p, uint32_t ibb_control_reg, uint32_t
next_snap, int instance, int temp_debug) {
    uint32_t next_address = (next_snap & IAT_ADDR_MASK);

    START;

    debug_out(("ibb_intr(%d): got address 0x%x set 0x%x\n",
	    instance,
	    *(ibb_p->fbac_virt),	
	    next_address));

    *(ibb_p->fbac_virt) = next_address;

    END;
}

static inline void
check_intr_delay(IbbSoftDev *ibb_p)
{
    START;

#ifdef TESTCAMDELAY
    hrtime_t snap_ndelay;
    hrtime_t ibb_ntimestamp;

    /* this may be useful but only in fly mode */
    ibb_ntimestamp = gethrtime();

    debug_out(("ibb_intr: ibbtime %llu\n",ibb_ntimestamp / 1000000));
    debug_out(("ibb_intr: rtctime %llu\n", ishared.rtc_ntimestamp));

    if (ibb_ntimestamp < ishared.rtc_ntimestamp) {
	debug_out(("ibb_intr: Bad value %llu for rtc intr\n", 
		ishared.rtc_ntimestamp));
    }

    snap_ndelay = ibb_ntimestamp - ishared.rtc_ntimestamp;

    if (snap_ndelay < kMinSnapDelay) {
	debug_out(("ibb_intr: grab snap delay %lld too short\n",
		snap_ndelay / 1000000));

	ibb_p->ushared->badsnap = kIbbShortSnap;
    }

    else if (snap_ndelay > kMaxSnapDelay) {
	debug_out(("ibb_intr: grab snap delay %lld too long\n",
		snap_ndelay / 1000000));

	ibb_p->ushared->badsnap = kIbbLongSnap;
    }

#endif

    END;
    return;
}

irqreturn_t
ibb_intr(int irq, void *dev_id, struct pt_regs *regs) {
    IbbSoftDev *ibb_sp = dev_id;

    uint32_t creg_val;
    uint32_t intr_set;
    uint32_t last_snap;
    uint32_t next_snap;

    int	instance;
    int temp_debug = 100;

    u_long flags;

    START;

    if (ibb_sp == NULL) {
	debug_out(("ERROR: ibb_intr: ibb_sp = NULL\n"));
	return(IRQ_NONE);
    }

    lock_ibb(ibb_sp, &flags, "ibb_intr");
    instance = ibb_sp->dev_num;
    creg_val = *ibb_sp->creg_virt;

    if (!(creg_val & ICR_INTR_PENDING)) {
	debug_out(("ibb_intr(%d): Not mine\n", ibb_sp->dev_num));

	unlock_ibb(ibb_sp, &flags, "ibb_intr Error");
	return(IRQ_NONE);
    }

    if (creg_val & ICR_CAM_FAIL) {
    	debug_out(("ibb_intr(%d): Camera Failure\n",ibb_sp->dev_num));
    }

    /* RESET INTR set ICR_INTR_CLEAR hi and remove software intrs*/

    intr_set =
	(ICR_INTR_CLEAR | creg_val | ICR_CLR_CAM_FAIL)
	& ~(ICR_SOFT_IMAGE | ICR_SIM_FIRE);

    *ibb_sp->creg_virt = intr_set;

    if (ibb_sp->ushared != NULL && ibb_sp->image_table != NULL) {
	ibb_sp->ushared->badsnap = 0;
	last_snap =
ibb_sp->image_table[ibb_sp->ushared->image_table_index];

	if (ibb_sp->height_inspection) {
	    uint32_t *address_start;
	    uint32_t *last_frame;

	    uint32_t height_data;
	    uint32_t last_address;

	    uint32_t last_fb = (last_snap & IAT_FB_MASK) >>
IAT_FB_SHIFT;

	    if (last_fb == 0) {
		address_start = ibb_sp->fb0_virt;
	    }
	    else {
		address_start = ibb_sp->fb1_virt;
	    }

	    last_address = last_snap & IAT_ADDR_MASK;
	    last_frame = address_start + last_address;

	    height_data = *(ibb_sp->height_virt);
	    height_data <<= 16;

	    *(last_frame) = height_data;
	}

	last_snap = last_snap | IAT_SNAP_DONE;
	ibb_sp->image_table[ibb_sp->ushared->image_table_index] =
last_snap;

	ibb_sp->ushared->image_table_index++;

	debug_out(("ibb_intr(%d): set index %d\n",
		ibb_sp->dev_num,
		ibb_sp->ushared->image_table_index));

	next_snap =
ibb_sp->image_table[ibb_sp->ushared->image_table_index];

	debug_out(("ibb_intr(%d): got next entry %d %x\n",instance,
		ibb_sp->ushared->image_table_index,
		next_snap));

	creg_val = *ibb_sp->creg_virt;
	debug_out(("ibb_intr(%d): set %x intr %x\n", 
		ibb_sp->dev_num,
		intr_set,
		creg_val));

	set_next_fb(ibb_sp->creg_virt, next_snap, instance, temp_debug);
	set_next_camera(ibb_sp->creg_virt, next_snap, instance,
temp_debug);
	set_next_address(ibb_sp, creg_val, next_snap, instance,
temp_debug);

        debug_out(("ibb_intr(%d): fbacount 0x%x\n",
		instance,
		*(ibb_sp->fbac_virt)));

	if (ibb_sp->flags & kIoWaiting) {
	    debug_out(("ibb_intr(%d): waiting for ind %d got %d\n",
		    instance,
		    ibb_sp->wait_for,
		    ibb_sp->ushared->image_table_index));

	    if (ibb_sp->ushared->image_table_index > ibb_sp->wait_for) {
		debug_out(("ibb_intr(%d): wake up wait queue\n",
			ibb_sp->dev_num));

		wake_up_interruptible(&ibb_sp->wq);
	    }
	}

	check_intr_delay(ibb_sp);
    }

    barrier();

    *ibb_sp->creg_virt =
	(~(ICR_INTR_CLEAR|ICR_CLR_CAM_FAIL) & *ibb_sp->creg_virt);

    unlock_ibb(ibb_sp, &flags, "ibb_intr");

    debug_out(("irqreturn_t ibb_intr - DONE!\n"));

    END;
    return(IRQ_HANDLED);
}

void
ibb_rtc_wakeup(void)
{
    int i;
    u_long flags;

    START;

    for (i = 0; i < kMaxIbbs; i++) {
	if (IbbSoft[i] != NULL) {
	    lock_ibb(IbbSoft[i], &flags, "ibb_rtc_wakeup");

	    IbbSoft[i]->wait_for = kIbbWakeup;
	    IbbSoft[i]->ushared->image_table_index =
IbbSoft[i]->wait_for + 1;

	    unlock_ibb(IbbSoft[i], &flags, "ibb_rtc_wakeup");
	    wake_up_interruptible(&IbbSoft[i]->wq);
	}
    }

    END;
}

module_init(ibb_init_module);
module_exit(ibb_cleanup_module);




:b!

Brian D. McGrew { [email protected] || [email protected] }
--
> This is a test.  This is only a test!
  Had this been an actual emergency, you would have been
  told to cancel this test and seek professional assistance!

-----Original Message-----
From: Arjan van de Ven [mailto:[email protected]] 
Sent: Thursday, May 18, 2006 6:51 PM
To: Brian D. McGrew
Cc: [email protected]
Subject: Re: Invalid module format?

On Thu, 2006-05-18 at 07:01 -0700, Brian D. McGrew wrote:
> I have two device drivers for two separate PCI cards.
> 
> Using the 2.6.15.6 I can compile and insert both of these drivers.
> 
> I copy my sources to my 2.6.16.16 tree and recompile them.  One driver
> inserts just fine (and works) and the other gives me this:
> 
> FATAL: Error inserting ibb
> (/lib/modules/2.6.16.16/kernel/drivers/mvp/ibb.ko): Invalid module
> format
> 
> The same source file between both kernels and I get no errors at
compile
> time.

you forgot to
1) look into dmesg and give us the information that gets printed there
   when modprobe returns this error
2) point to the source of the driver



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux