Messages in this thread | | | Subject | RE: Invalid module format? | Date | Fri, 19 May 2006 10:11:48 -0700 | From | "Brian D. McGrew" <> |
| |
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
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |