RE: Invalid module format?

Brian D. McGrew
2006-05-19T17:11:52Z

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 { brian@visionpro.com || brian@doubledimension.com }
--
> 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:arjan@infradead.org]
Sent: Thursday, May 18, 2006 6:51 PM
To: Brian D. McGrew
Cc: linux-kernel@vger.kernel.org
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