My drivers are inline in this mail. I'm still having this problem with
the 2.6.16 kernel as where I'm not having it with the 2.6.15 kernel --
and it's the same source code, compiled the same way.
Also, I'm still having difficulties getting this driver to work
correctly so any help would be great!
-->
/usr/src/redhat/BUILD/kernel-2.6.16.16/linux-2.6.16.16/drivers/mvp/mvp_r
tc.c
static const char *rtc_c = "$Id: mvp_rtc.c,v 1.3 2006/04/18 21:20:36
brian Exp brian $ (c) MVP ";
#include <asm/io.h> /* ioremap */
#include <asm/uaccess.h> /* put_user */
#include <linux/config.h> /* access CONFIG_PCI macro */
#include <linux/fs.h>
#include <linux/interrupt.h> /* request/free_irq */
#include <linux/mm.h> /* memory mapping */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/types.h>
#include "dev/rtc.h"
#include "rtcsoft.h"
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#ifndef CONFIG_PCI
#error "This driver REQUIRES PCI support"
#endif
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define
MODVERSIONS /* force it on */ #endif
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif
#ifdef CONFIG_DEVFS_FS
devfs_handle_t rtc_devfs_dir;
#endif
#define TYPE(dev) (MINOR(dev) >> 4) /* high nibble */
#define NUM(dev) (MINOR(dev) & 0xf) /* low nibble */
#define kOneByteShift 8
extern void ibb_rtc_wakeup(void);
irqreturn_t rtc_intr(int irq, void *dev_id, struct pt_regs *regs);
static RtcSoftDev *RtcSoft[kNrtc];
#define DEBUG
#ifdef DEBUG
#define debug_out(msg) { printk msg; }
#else
#define debug_out(msg)
#endif
static void
lock_rtc(RtcSoftDev *rtc_sp, unsigned long *flags, const char *where) {
debug_out(("lock_rtc(%d): %s:\n", rtc_sp->dev_num, where));
spin_lock_irqsave(&rtc_sp->mutex, *flags);
debug_out(("lock_rtc(%d): Done %s:\n", rtc_sp->dev_num, where)); }
static void
unlock_rtc(RtcSoftDev *rtc_sp, unsigned long *flags, const char *where)
{
debug_out(("unlock_rtc(%d): %s:\n", rtc_sp->dev_num, where));
spin_unlock_irqrestore(&rtc_sp->mutex, *flags);
debug_out(("unlock_rtc(%d): %s:\n", rtc_sp->dev_num, where)); }
static void
init_rtc_soft_state(void)
{
int i;
for (i = 0; i < kNrtc; i++) {
RtcSoft[i] = NULL;
}
}
static int
alloc_rtc_soft_state(void)
{
int i;
for (i = 0; i < kNrtc; i ++) {
if (RtcSoft[i] == NULL) {
RtcSoft[i] = kmalloc(sizeof(RtcSoftDev), GFP_KERNEL);
if (RtcSoft[i] == NULL) {
debug_out(("alloc_rtc_soft_state: out of memory.\n"));
return(-1);
}
debug_out(("alloc_rtc_soft_state: return %d\n", i));
return(i);
}
}
return(-1);
}
/*
* There may be a better way to do this!
*
* I need to make sure the data I initialized in rtc_probe()
* for device "X" is the same data I use in rtc_open().
*
* I could use the minor numbers, but I have to trust that
* the 'load' script for the rtc device is written correctly,
* since that's where minor numbers are assigned.
*
* So I'm using the major numbers. It's a little slower, since
* major numbers tend to be >200 I'm not just going to use
* them as indexes into my array. Instead I'm going though
* all the devices looking for the matching major.
*
* My concern, frankly, is that no other drivers seem to be
* using this method. But it seems the only foolproof way
* to keep the data with the device
*/
static int
find_rtc_soft_state(int rtc_major)
{
int i;
debug_out(("find_rtc_soft_state: major %d\n", rtc_major));
for (i = 0; i < kNrtc; i++) {
if (RtcSoft[i] != NULL) {
if( rtc_major == RtcSoft[i]->rtc_major) {
debug_out(("find_rtc_soft_state: return %d\n", i));
return(i);
}
}
}
debug_out(("Can't find matching soft_state %d!\n", rtc_major));
return(-1);
}
static void
free_rtc_soft_state(int i)
{
if (RtcSoft[i] == NULL)
return;
debug_out(("free_rtc_soft_state(%d):\n", RtcSoft[i]->dev_num));
kfree(RtcSoft[i]);
RtcSoft[i] = NULL;
return;
}
ssize_t
rtc_read(struct file *filp, char * buf, size_t count, loff_t *f_pos) {
return(-EINVAL);
}
ssize_t
rtc_write(struct file *filp, const char *buf, size_t count, loff_t
*f_pos) {
return(-EINVAL);
}
int
rtc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long __user arg) {
RtcSoftDev *rtc_sp = filp->private_data;
RtcStrobes rtc_light;
struct timeval tv;
u_long ecounts;
u_long flags;
int retval = 0;
uint16_t i;
uint16_t light_mask;
uint32_t control_reg;
uint32_t fireoff;
uint32_t fireon;
uint32_t reset;
uint32_t set;
uint32_t strobe_timer;
uint32_t strobe_timer_mask;
volatile uint32_t StartInspecting;
if (rtc_sp == NULL) {
debug_out(("rtc_ioctl: Soft Info Lost\n"));
return(-EFAULT);
}
switch(cmd) {
case RTCBONVOYAGE:
debug_out(("RTCBONVOYAGE\n"));
do_gettimeofday(&tv);
lock_rtc(rtc_sp, &flags, "RTCBONVOYAGE");
rtc_sp->shared_host_mem->ntimestamp = tv.tv_sec;
rtc_sp->snap_int_virt[kLastSnapLoc] = FIRST_SCAN;
StartInspecting = rtc_sp->snap_int_virt[kLastSnapLoc];
unlock_rtc(rtc_sp, &flags, "RTCBONVOYAGE");
debug_out(("RTCBONVOYAGE - DONE\n"));
break;
case RTCWAKEUP:
debug_out(("RTCWAKEUP\n"));
ibb_rtc_wakeup();
debug_out(("RTCWAKEUP - DONE\n"));
break;
case RTC_STROBEPROG_ON:
debug_out(("RTC_STROBEPROG_ON\n"));
if (copy_from_user((void *)rtc_light,
(const void *)__user arg,
sizeof(RtcStrobes)))
{
debug_out(("rtc_ioctl: can't copy RtcStrobes %lx %d\n",
arg, sizeof(RtcStrobes)));
return(EFAULT);
}
lock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_ON");
light_mask = 0;
strobe_timer = 0;
for (i = 0; i < kMaxRtcRings; i++) {
if (rtc_light[i].hw_time > -1) {
debug_out(("rtc_ioctl: Enter time 0x%x for ring
%d\n",
rtc_light[i].hw_time,i));
light_mask |= (1 << (i));
strobe_timer_mask = rtc_light[i].hw_time;
strobe_timer_mask = strobe_timer_mask <<(i *
kOneByteShift);
strobe_timer = strobe_timer | strobe_timer_mask;
}
}
*(rtc_sp->strobe_virt) = strobe_timer;
control_reg = *(rtc_sp->control_virt);
/* turn off all lights before putting in the ones we want */
control_reg &= ~ RCR_ALLLIGHTS;
if (light_mask == 0) {
control_reg &= ~RCR_STROBEPROG;
}
else {
light_mask = light_mask << 4;
control_reg |= RCR_STROBEPROG;
control_reg |= light_mask;
}
*(rtc_sp->control_virt) = control_reg;
unlock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_ON");
debug_out(("rtc_ioctl:control_reg at %#x\n", control_reg));
debug_out(("rtc_ioctl:strobe_reg at %#x\n", strobe_timer));
debug_out(("RTC_STROBEPROG_ON - DONE\n"));
break;
case RTC_STROBEPROG_OFF:
/* set byte 0 in control reg to 0 */
debug_out(("RTC_STROBEPROG_OFF\n"));
lock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_OFF");
*(rtc_sp->control_virt) &= ~RCR_ALLLIGHTS;
debug_out(("rtc_ioctl:control_reg at %#x\n",
*(rtc_sp->control_virt)));
*(rtc_sp->control_virt) &= ~RCR_STROBEPROG;
debug_out(("rtc_ioctl:control_reg at %#x\n",
*(rtc_sp->control_virt)));
unlock_rtc(rtc_sp, &flags, "RTC_STROBEPROG_OFF");
debug_out(("RTC_STROBEPROG_OFF - DONE\n"));
break;
case RTCFIRESTROBE:
/* set and reset bit 1 in control register */
debug_out(("RTCFIRESTROBE\n"));
lock_rtc(rtc_sp, &flags, "RTCFIRESTROBE");
fireoff = *(rtc_sp->control_virt);
fireon = fireoff | RCR_FIRESTROBE;
*(rtc_sp->control_virt) = fireon;
*(rtc_sp->control_virt) = fireoff;
unlock_rtc(rtc_sp, &flags, "RTCFIRESTROBE");
debug_out(("RTCFIRESTROBE - DONE\n"));
break;
case RTCSTARTECOUNT:
/*
* we need to set this bit so the encoder counts will be
* available to our encoder_regp regisert.
*/
debug_out(("RTCSTARTECOUNT\n"));
lock_rtc(rtc_sp, &flags, "RTCSTARTECOUNT");
*(rtc_sp->control_virt) |= RCR_ECOUNTON;
unlock_rtc(rtc_sp, &flags, "RTCSTARTECOUNT");
debug_out(("RTCSTARTECOUNT - DONE\n"));
break;
case RTCGETECOUNT:
debug_out(("RTCGETECOUNT\n"));
lock_rtc(rtc_sp, &flags, "RTCGETECOUNT");
ecounts = *(rtc_sp->encoder_virt);
if (put_user(ecounts, (unsigned long *)__user arg)) {
debug_out(("rtc_ioctl: can't copy encoder counts %lx
%d\n",
ecounts, sizeof(long)));
retval = -EFAULT;
}
/*
* clear the bit
*/
*(rtc_sp->control_virt) &= ~RCR_ECOUNTON;
unlock_rtc(rtc_sp, &flags, "RTCGETECOUNT");
debug_out(("RTCGETECOUNT - DONE\n"));
break;
case RTCRESETSNAP:
/*
* if there has been an estop or a software crash, it's
possible
* the RTC state machine has gotten confused. Setting and
reseting
* bit 15 will clear the state machine so it's ready for new
* inspections
*/
debug_out(("RTCRESETSNAP\n"));
lock_rtc(rtc_sp, &flags, "RTCRESETSNAP");
reset = *(rtc_sp->control_virt);
set = reset | RCR_SRESET;
*(rtc_sp->control_virt) = set;
*(rtc_sp->control_virt) = reset;
unlock_rtc(rtc_sp, &flags, "RTCRESETSNAP");
debug_out(("RTCRESETSNAP - DONE\n"));
break;
case RTC_STAGE_NON_LINEAR:
/*
* change the dig cam compensation distance for non-linear
* stages, which have fewer encoder counts per inch
*/
debug_out(("RTC_STAGE_NON_LINEAR\n"));
lock_rtc(rtc_sp, &flags, "RTC_STAGE_NON_LINEAR");
*(rtc_sp->control_virt) |= RCR_COMPSIZE;
unlock_rtc(rtc_sp, &flags, "RTC_STAGE_NON_LINEAR");
debug_out(("RTC_STAGE_NON_LINEAR - DONE\n"));
break;
case RTCVERSION:
debug_out(("RTCVERSION\n"));
lock_rtc(rtc_sp, &flags, "RTCVERSION");
if (put_user(kRtcVersion, (unsigned long *)__user arg)) {
debug_out(("rtc_ioctl: can't copy Version info %ld\n",
kRtcVersion));
retval = -EFAULT;
}
unlock_rtc(rtc_sp, &flags, "RTCVERSION");
debug_out(("rtc_ioctl: COPIED Version info %ld\n",
kRtcVersion));
debug_out(("RTCVERSION - DONE\n"));
break;
default:
debug_out(("rtc_ioctl: unknown case: %d\n", cmd));
debug_out(("RTC---WTF\n"));
retval = -ENOTTY;
}
return(retval);
}
/*
* just make sure the area mmap is requesting falls within
* valid areas for the RTC card
*/
/* our off - 0x20000
* our phys_off - 0x20000
* our phys_diff - 0x20000
*/
int
rtc_mmap(struct file *filep, struct vm_area_struct *vma) {
RtcSoftDev *rtc_sp = filep->private_data;
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page = ((rtc_sp->iobase + offset) >> PAGE_SHIFT);
if (offset > __pa(high_memory) || (filep->f_flags & O_SYNC)) {
vma->vm_flags |= VM_IO;
}
vma->vm_flags |= VM_RESERVED;
if (offset == RTC_SNAP_INTERVAL_OFFSET) {
debug_out(("RTC_SNAP_INTERVAL_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_DIGIO_OFFSET) {
debug_out(("RTC_DIGIO_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_STROBE_TIMER_OFFSET) {
debug_out(("RTC_STROBE_TIMER_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_CONTROL_REG_OFFSET) {
debug_out(("RTC_CONTROL_REG_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_ENCODER_CNT_OFFSET) {
debug_out(("RTC_ENCODER_CNT_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_GRAPHICS_REG_OFFSET) {
debug_out(("RTC_GRAPHICS_REG_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_CY545_TRANS_OFFSET) {
debug_out(("RTC_CY545_TRANS_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_CY545_CONTROL_OFFSET) {
debug_out(("RTC_CY545_CONTROL_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_GRAPHICS_MEM_OFFSET) {
debug_out(("RTC_GRAPHICS_MEM_OFFSET: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else if (offset == RTC_COMMON_VADDR) {
debug_out(("RTC_COMMON_VADDR: %x\n", offset));
while (size > 0) {
debug_out(("START: %x, SIZE: %x, OFFSET: %x, PAGE: %x\n",
start, size, offset, page));
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
else {
debug_out(("RTC_???_OFFSET --- WE'RE BROKEN --- %x\n", offset));
}
return(0);
}
int
rtc_open(struct inode *inode, struct file *filep) {
RtcSoftDev *rtc_sp;
int dev_num;
int major = MAJOR(inode->i_rdev);
int minor = MINOR(inode->i_rdev);
/*
* the type and num values are only valid if we are not using devfs.
* hmm - sounds bad
*/
/*
* assign the private data so we can access it later
* ( in read, write, ioctl, etc );
*/
debug_out(("rtc_open: major %d minor %d\n", major, minor));
dev_num = find_rtc_soft_state(major);
if (dev_num < 0) {
debug_out(("rtc_open: dev_num %d failed\n", dev_num));
return(-1);
}
rtc_sp = RtcSoft[dev_num];
filep->private_data = rtc_sp;
debug_out(("rtc opened by %s pid %d PAGE_SIZE %#lx\n",
current->comm, current->pid, PAGE_SIZE));
return(0);
}
int
rtc_close( struct inode *inode, struct file *filep ) {
return(0);
}
struct file_operations rtc_fops = {
read: rtc_read,
write: rtc_write,
ioctl: rtc_ioctl,
mmap: rtc_mmap,
open: rtc_open,
release: rtc_close,
};
static int
free_rtc_usr_shared(RtcSoftDev *rtc_sp)
{
unsigned long virt_addr;
struct page *page;
/* unreserve all pages */
for (virt_addr = (unsigned long) rtc_sp->shared_host_mem;
virt_addr < (unsigned long) rtc_sp->shared_host_mem +
RTC_COMMON_SIZE;
virt_addr+=PAGE_SIZE)
{
page = virt_to_page(virt_addr);
ClearPageReserved(page);
// atomic_set(&page->_count, 1);
free_page(virt_addr);
}
if (rtc_sp->shared_host_mem) {
rtc_sp->shared_host_mem = NULL;
}
return(0);
}
static int
alloc_rtc_usr_shared(RtcSoftDev *rtc_sp) {
unsigned long virt_addr;
int order = 0;
/*
* get a memory area with kmalloc and aligned it to a page. This
area
* will be physically contigous
*/
while (RTC_COMMON_SIZE > (PAGE_SIZE * (1 << order))) {
order++;
}
rtc_sp->shared_host_mem = (RtcShared *)__get_free_pages(GFP_KERNEL,
order);
if (rtc_sp->shared_host_mem == NULL) {
debug_out(("alloc_rtc_usr_shared: out of memory.\n"));
return(-1);
}
for (virt_addr = (unsigned long)rtc_sp->shared_host_mem;
virt_addr < (unsigned
long)rtc_sp->shared_host_mem+RTC_COMMON_SIZE;
virt_addr += PAGE_SIZE)
{
/* reserve all pages to make them remapable */
SetPageReserved(virt_to_page(virt_addr));
}
return(0);
}
static void
free_all_mappings(RtcSoftDev *rtc_sp)
{
if (rtc_sp->snap_int_virt != NULL) {
iounmap(rtc_sp->snap_int_virt);
rtc_sp->snap_int_virt = NULL;
}
/*
* we can call release_mem_region() without checking anything -
* if the region hasn't been requested, the function will
* just exit with an error message.
* ( unlink iounmap() )
*/
release_mem_region(rtc_sp->snap_int_phys, rtc_sp->snap_int_size);
if (rtc_sp->digio_virt != NULL) {
iounmap(rtc_sp->digio_virt);
rtc_sp->digio_virt = NULL;
}
release_mem_region(rtc_sp->digio_phys, rtc_sp->digio_size);
if (rtc_sp->strobe_virt != NULL) {
iounmap(rtc_sp->strobe_virt);
rtc_sp->strobe_virt = NULL;
}
release_mem_region(rtc_sp->strobe_phys, rtc_sp->strobe_size);
if (rtc_sp->control_virt != NULL) {
iounmap(rtc_sp->control_virt);
rtc_sp->control_virt = NULL;
}
release_mem_region(rtc_sp->control_phys, rtc_sp->control_size);
if (rtc_sp->encoder_virt != NULL) {
iounmap(rtc_sp->encoder_virt);
rtc_sp->encoder_virt = NULL;
}
release_mem_region(rtc_sp->encoder_phys, rtc_sp->encoder_size);
if (rtc_sp->graphics_reg_virt != NULL) {
iounmap(rtc_sp->graphics_reg_virt);
rtc_sp->graphics_reg_virt = NULL;
}
release_mem_region(rtc_sp->graphics_reg_phys,
rtc_sp->graphics_reg_size);
if (rtc_sp->cy545_trans_virt != NULL) {
iounmap(rtc_sp->cy545_trans_virt);
rtc_sp->cy545_trans_virt = NULL;
}
release_mem_region(rtc_sp->cy545_trans_phys,
rtc_sp->cy545_trans_size);
if (rtc_sp->cy545_cr_virt != NULL) {
iounmap(rtc_sp->cy545_cr_virt);
rtc_sp->cy545_cr_virt = NULL;
}
release_mem_region(rtc_sp->cy545_cr_phys, rtc_sp->cy545_cr_size);
if (rtc_sp->graphics_mem_virt != NULL) {
iounmap(rtc_sp->graphics_mem_virt);
rtc_sp->graphics_mem_virt = NULL;
}
release_mem_region(rtc_sp->graphics_mem_phys,
rtc_sp->graphics_mem_size);
if (rtc_sp->shared_host_mem != NULL) {
free_rtc_usr_shared(rtc_sp);
}
}
static int
rtc_map_one(RtcSoftDev *rtc_sp, u_long phys, u_long size, uint32_t
**virt, const char *what)
{
struct resource *res;
if ((res = request_mem_region(phys,size,rtc_sp->devname)) == NULL) {
debug_out(("rtc_map_one(%d): can't allocate %s at %010lx %#010lx
%s\n",
rtc_sp->dev_num, what, phys, size, rtc_sp->devname));
return(-1);
}
else {
*virt = ioremap_nocache(phys, size);
if (!virt) {
debug_out(("rtc_map_one(%d): Error in ioremap\n",
rtc_sp->dev_num));
release_mem_region(phys, size);
return(-1);
}
}
debug_out(("rtc_map_one(%d): Successful map %s: Phys %#lx\n",
rtc_sp->dev_num, what, phys));
return(0);
}
static int
rtc_do_all_mappings(RtcSoftDev *rtc_sp)
{
rtc_sp->snap_int_virt = NULL;
rtc_sp->digio_virt = NULL;
rtc_sp->strobe_virt = NULL;
rtc_sp->control_virt = NULL;
rtc_sp->encoder_virt = NULL;
rtc_sp->graphics_reg_virt = NULL;
rtc_sp->cy545_trans_virt = NULL;
rtc_sp->cy545_cr_virt = NULL;
rtc_sp->graphics_mem_virt = NULL;
/* Map Snap Interval */
rtc_sp->snap_int_phys = rtc_sp->iobase + RTC_SNAP_INTERVAL_OFFSET;
rtc_sp->snap_int_size = RTC_SNAP_INTERVAL_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->snap_int_phys,
rtc_sp->snap_int_size,
&rtc_sp->snap_int_virt,
"Snap Interval") < 0)
{
return(-1);
}
/* Map Digital I/O */
rtc_sp->digio_phys = rtc_sp->iobase + RTC_DIGIO_OFFSET;
rtc_sp->digio_size = RTC_DIGIO_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->digio_phys,
rtc_sp->digio_size,
&rtc_sp->digio_virt,
"Digital I/O") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map Strobe Timer */
rtc_sp->strobe_phys = rtc_sp->iobase + RTC_STROBE_TIMER_OFFSET;
rtc_sp->strobe_size = RTC_STROBE_TIMER_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->strobe_phys,
rtc_sp->strobe_size,
&rtc_sp->strobe_virt,
"Strobe Timer") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map Control Register */
rtc_sp->control_phys = rtc_sp->iobase + RTC_CONTROL_REG_OFFSET;
rtc_sp->control_size = RTC_CONTROL_REG_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->control_phys,
rtc_sp->control_size,
&rtc_sp->control_virt,
"Control Reg") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map Encoder Counter */
rtc_sp->encoder_phys = rtc_sp->iobase + RTC_ENCODER_CNT_OFFSET;
rtc_sp->encoder_size = RTC_ENCODER_CNT_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->encoder_phys,
rtc_sp->encoder_size,
&rtc_sp->encoder_virt,
"Encoder Counter") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map Graphics Register */
rtc_sp->graphics_reg_phys = rtc_sp->iobase +
RTC_GRAPHICS_REG_OFFSET;
rtc_sp->graphics_reg_size = RTC_GRAPHICS_REG_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->graphics_reg_phys,
rtc_sp->graphics_reg_size,
&rtc_sp->graphics_reg_virt,
"Graphics Register") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map CY545 Trans Reg */
rtc_sp->cy545_trans_phys = rtc_sp->iobase + RTC_CY545_TRANS_OFFSET;
rtc_sp->cy545_trans_size = RTC_CY545_TRANS_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->cy545_trans_phys,
rtc_sp->cy545_trans_size,
&rtc_sp->cy545_trans_virt,
"CY545 Trans Reg") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map CY545 Control Reg */
rtc_sp->cy545_cr_phys = rtc_sp->iobase + RTC_CY545_CONTROL_OFFSET;
rtc_sp->cy545_cr_size = RTC_CY545_CONTROL_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->cy545_cr_phys,
rtc_sp->cy545_cr_size,
&rtc_sp->cy545_cr_virt,
"CY545 Control Reg") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
/* Map Graphics Memory */
rtc_sp->graphics_mem_phys = rtc_sp->iobase +
RTC_GRAPHICS_MEM_OFFSET;
rtc_sp->graphics_mem_size = RTC_GRAPHICS_MEM_SIZE;
if (rtc_map_one(rtc_sp,
rtc_sp->graphics_mem_phys,
rtc_sp->graphics_mem_size,
&rtc_sp->graphics_mem_virt,
"Graphics Memory") < 0)
{
free_all_mappings(rtc_sp);
return(-1);
}
if (alloc_rtc_usr_shared(rtc_sp) < 0) {
free_all_mappings(rtc_sp);
return(-1);
}
return(0);
}
static int __initdata
rtc_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) {
RtcSoftDev *rtc_sp;
char revid = ' ';
u8 rev_id = 0;
u16 device_id;
int result;
int dev_num;
int rtc_major;
int intr_handler_req;
if (pci_enable_device(pdev)) {
return(-ENODEV);
}
/* stealing code from cciss.c - thanks compaq! */
debug_out(("rtc_probe: RTC 0x%08x found @bus %d dev %d func %d\n",
pdev->device,
pdev->bus->number,
PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn)));
/* alloc our per-device data */
dev_num = alloc_rtc_soft_state();
if (dev_num < 0) {
/* I've already printk'd error message */
return(-ENOMEM);
}
result = 0;
memset(RtcSoft[dev_num], 0, sizeof(RtcSoft[dev_num]));
rtc_sp = RtcSoft[dev_num];
sprintf(rtc_sp->devname, "mvp_rtc");
spin_lock_init(&rtc_sp->mutex);
rtc_sp->dev_num = dev_num;
rtc_sp->pdev = pdev;
sema_init(&rtc_sp->sem, 1);
pci_set_drvdata(pdev,rtc_sp); /* we'll need this in remove: */
debug_out(("rtc_probe: device %d\n", dev_num));
#define REQUESTMEM
#ifdef REQUESTMEM
/*
* map the card memory areas into kernel space
* and store the address in our RtcDev info
*/
rtc_sp->iobase = pci_resource_start(pdev, 0);
rtc_sp->iosize = pci_resource_len(pdev, 0);
debug_out(("rtc_probe_module: base start %#010lx size %#010lx\n",
rtc_sp->iobase,
rtc_sp->iosize));
if (rtc_do_all_mappings(rtc_sp) < 0) {
debug_out(("rtc_probe: do_all_mappings failed\n"));
free_rtc_soft_state(rtc_sp->dev_num);
return(-ENODEV);
}
#endif
#ifdef CONFIG_DEVFS_FS
rtc_sp->rtc_devfs_dir = devfs_mk_dir(NULL, rtc_sp->devname, NULL);
if (!rtc_sp->rtc_devfs_dir) {
debug_out(("rtc_probe(%d): can't register devfs\n", dev_num));
free_all_mappings(rtc_sp);
free_rtc_soft_state(rtc_sp->dev_num);
return(-EBUSY);
}
devfs_resister(rtc_sp->rtc_devfs_dir,
rtc_sp->devname,
DEVFS_FL_AUTO_DEVNUM, /* autoallocate
major/minor */
0, /* ignored because of
flag */
0, /* ignored because of
flag */
S_IFCHR | S_IRUGO | S_IWUGO, /* ??? */
&rtc_fops,
rtc_sp);
#else
rtc_major = 0;
result = register_chrdev(rtc_major, rtc_sp->devname, &rtc_fops);
if (result < 0) {
debug_out(("rtc_probe_module: can't get major %d\n",
rtc_major));
free_all_mappings(rtc_sp);
free_rtc_soft_state(rtc_sp->dev_num);
return(-EBUSY);
}
if (rtc_major == 0) {
rtc_major = result;
}
debug_out(("rtc_probe_module: got major %d\n", rtc_major));
#endif
rtc_sp->rtc_major = rtc_major;
pci_read_config_word(pdev, 2, &device_id);
pci_read_config_byte(pdev, 8, &rev_id);
if (rev_id > 0 && rev_id < 27) {
rev_id += 0x40;
revid = rev_id;
}
if (!pdev->irq) {
debug_out(("rtc_probe_module: can't get interrupt number\n"));
free_all_mappings(rtc_sp);
free_rtc_soft_state(rtc_sp->dev_num);
return(-ENODEV);
}
rtc_sp->myint = pdev->irq;
rtc_sp->irq_cnt = 0;
intr_handler_req = request_irq(rtc_sp->myint,rtc_intr,
SA_SHIRQ,
rtc_sp->devname,
rtc_sp);
if (intr_handler_req != 0) {
debug_out(("rtc_probe_module: can't req interrupt handler\n"));
free_all_mappings(rtc_sp);
free_rtc_soft_state(rtc_sp->dev_num);
return(-ENODEV);
}
debug_out(("MVP Real Time Controller Board A: %s%d, %X.%c, Int:
%d\n",
RTC_DEVICE, dev_num, device_id, revid, rtc_sp->myint));
debug_out(("driver(%d) %s\n", dev_num, rtc_c));
return(result);
}
static void __exitdata
rtc_remove(struct pci_dev *pci_dev)
{
RtcSoftDev *rtc_sp = (RtcSoftDev *)pci_get_drvdata(pci_dev);
if (rtc_sp == NULL) {
debug_out(("rtc_remove: Error: Null RTC Data in remove\n"));
return;
}
debug_out(("rtc_remove:\n"));
unregister_chrdev(rtc_sp->rtc_major, rtc_sp->devname);
free_irq(rtc_sp->myint, rtc_sp);
rtc_sp->myint = 0;
free_all_mappings(rtc_sp);
free_rtc_soft_state(rtc_sp->dev_num);
}
static struct pci_device_id rtc_id_table[] __devinitdata = {
{ 0x8f73, 0xa1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x8f73, 0xa2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 } };
/*
* have _no idea_ why I'm calling this - find out!
*
* from /usr/inluclude/linux/module.h
* MODULE_DEVICE_TABLE exports information about devices
* currently supported by this module. A device type, such as PCI,
* is a C-like identifier passed as the first arg to this macro.
* The second macro arg is the variable containing the device
* information being made public.
*
* The following is a list of known device types (arg 1),
* and the C types which are to be passed as arg 2.
* pci - struct pci_device_id - List of PCI ids supported by this module
* isapnp - struct isapnp_device_id -
* List of ISA PnP ids supported by this module
* usb - struct usb_device_id - List of USB ids supported by this module
*
* still - ok so it exports it, who imports it and what do they
* do with it?
*/
MODULE_DEVICE_TABLE(pci, rtc_id_table);
struct pci_driver rtc_driver = {
name: "rtc0",
id_table: rtc_id_table,
probe: rtc_probe,
remove: rtc_remove,
};
int __init
rtc_init_module(void)
{
init_rtc_soft_state();
return(pci_module_init(&rtc_driver));
}
void __exit
rtc_cleanup_module(void)
{
pci_unregister_driver(&rtc_driver);
}
/*
* RTC interrupt routine. I could not get the outl() and inl() macros
to
* work using the physical address. So,using the virtual address of the
* hardware seems to work.
*/
irqreturn_t
rtc_intr(int irq, void *dev_id, struct pt_regs *regs) {
unsigned long creg_val = 0L;
struct timeval tv;
unsigned long flags;
RtcSoftDev *rtc_sp = dev_id;
if (rtc_sp == NULL) {
debug_out(("Rtc Intr: rtc_sp is NULL\n"));
return(IRQ_NONE);
}
lock_rtc(rtc_sp,&flags,"rtc_intr");
rtc_sp->irq_cnt++;
creg_val = *rtc_sp->control_virt;
if (!(creg_val & RCR_INTR)) {
debug_out(("rtc_intr: SNAPINT not set\n"));
unlock_rtc(rtc_sp, &flags, "rtc_intr Error");
return(IRQ_NONE);
}
if (rtc_sp->shared_host_mem != NULL) {
rtc_sp->shared_host_mem->snap_addrs_loc++;
do_gettimeofday(&tv);
rtc_sp->shared_host_mem->ntimestamp = tv.tv_sec;
debug_out(("rtc_intr: rtc_sp->shared_host_mem->snap_addrs_loc:
%d\n",
rtc_sp->shared_host_mem->snap_addrs_loc));
}
else {
debug_out(("rtc_intr: rtc_sp->shared_host_mem->snap_addrs_loc
NULL\n"));
}
*rtc_sp->control_virt |= RCR_INTRRESET;
barrier();
*rtc_sp->control_virt &= ~RCR_INTRRESET;
unlock_rtc(rtc_sp,&flags,"rtc_intr");
return(IRQ_HANDLED);
}
module_init(rtc_init_module);
module_exit(rtc_cleanup_module);
--->
/usr/src/redhat/BUILD/kernel-2.6.16.16/linux-2.16.16/dirvers/mvp/ibb.c
static const char *ibb_c = "$Id: ibb.c,v 1.5 2006/04/18 19:48:02 brian
Exp brian $(c) MVP ";
#include <asm/uaccess.h>
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "dev/ibb.h"
#include "ibbsoft.h"
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#ifndef CONFIG_PCI
#error "This driver REQUIRES PCI support!"
#endif
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define
MODVERSIONS #endif
void ibb_rtc_wakeup(void);
irqreturn_t ibb_intr(int irq, void *dev_id, struct pt_regs *regs);
EXPORT_SYMBOL(ibb_rtc_wakeup);
/*
* Split minors in two parts
*/
#define TYPE(dev) (MINOR(dev) >> 4) /* high nibble */
#define NUM(dev) (MINOR(dev) & 0xf) /* low nibble */
#define DEBUG
#ifdef DEBUG
#define debug_out(msg) { printk msg; }
#else
#define debug_out(msg)
#endif
/*
* Place the call to START at the begining of the function and place the
call
* to END where the function __should__ be returning at (not always at
the
* end of the function, get it)!
*/
#define START
#define END
#if 0
#define START { debug_out(("IBB_START: %s\n", __func__)); }
#define END { debug_out(("IBB_FINISH: %s\n", __func__)); }
#endif
/*
* array of devices
*/
static IbbSoftDev *IbbSoft[kMaxIbbs];
static const uint32_t kIoWaiting = 0x04;
static const uint32_t MAG_FB_NUMBER = 0xCE1E57E;
static const uint16_t kIbbWakeup = 0x0fff;
/*
* clamp the max frame buffer size to the lowest available memory size
*/ typedef struct ibb_ishared_attr {
u_int32_t frame_buffer_size;
int32_t dev_instance[kMaxIbbs];
} ibb_ishared_attr;
static ibb_ishared_attr ishared;
static void
lock_ibb(IbbSoftDev *ibb_sp, u_long *flags, const char *where) {
START;
debug_out(("lock_ibb(%d): %s:\n", ibb_sp->dev_num, where));
spin_lock_irqsave(&ibb_sp->mutex, *flags);
debug_out(("lock_ibb(%d): Done %s:\n", ibb_sp->dev_num, where));
END;
}
static void
unlock_ibb(IbbSoftDev *ibb_sp, u_long *flags, const char *where) {
START;
debug_out(("unlock_ibb(%d): %s:\n", ibb_sp->dev_num, where));
spin_unlock_irqrestore(&ibb_sp->mutex, *flags);
debug_out(("unlock_ibb(%d): Done %s:\n", ibb_sp->dev_num, where));
END;
}
static void
init_ibb_soft_state(void)
{
int i;
START;
for (i = 0; i < kMaxIbbs; i++)
IbbSoft[i] = NULL;
END;
}
static int
alloc_ibb_soft_state(void)
{
int i;
START;
for (i = 0; i < kMaxIbbs; i++) {
if (IbbSoft[i] == NULL) {
IbbSoft[i] = kmalloc(sizeof(IbbSoftDev), GFP_KERNEL);
if (IbbSoft[i] == NULL) {
debug_out(("alloc_ibb_soft_state: out of memory\n"));
return(-1);
}
debug_out(("alloc_ibb_soft_state: return %d\n", i));
END;
return(i);
}
}
return(-1);
}
/*
* There may be a better way to do this!
*
* I need to make sure the data I initialized in ibb_probe()
* for device "X" is the same data I use in ibb_open().
*
* I could use the minor numbers, but I have to trust that
* the 'load' script for the ibb device is written correctly,
* since that's where minor numbers are assigned.
*
* So I'm using the major numbers. It's a little slower, since
* major numbers tend to be >200 I'm not just going to use
* them as indexes into my array. Instead I'm going though
* all the devices looking for the matching major.
*
* My concern, frankly, is that no other drivers seem to be
* using this method. But it seems the only foolproof way
* to keep the data with the device
*/
static int
find_ibb_soft_state(int ibb_major)
{
int i;
START;
debug_out(("find_ibb_soft_state: major %d\n", ibb_major));
for (i = 0; i < kMaxIbbs; i++) {
if (IbbSoft[i] != NULL) {
if (ibb_major == IbbSoft[i]->ibb_major) {
debug_out(("find_ibb_soft_state: return %d\n", i));
END;
return(i);
}
}
}
debug_out(("Can't find matching soft_state %d!\n", ibb_major));
return(-1);
}
static void
free_ibb_soft_state(int i)
{
START;
if (IbbSoft[i] == NULL) {
debug_out(("IbbSoft[%d] is already free and null\n", i));
return;
}
debug_out(("free_ibb_soft_state(%d):\n", IbbSoft[i]->dev_num));
kfree(IbbSoft[i]);
IbbSoft[i] = NULL;
END;
return;
}
ssize_t
ibb_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
debug_out(("ibb_read: -EINVAL\n"));
return(-EINVAL);
}
ssize_t
ibb_write(struct file *filp, const char *buf, size_t count, loff_t
*f_pos) {
debug_out(("ibb_write: -EINVAL\n"));
return(-EINVAL);
}
/*
* IBBWAIT ioctl routine
* wait for ushared->image_table_index to *exceed* value
* passed in - (IBBWAIT,0) waits for snap 0 to be processed and
* index to advance to 1
*/
static inline int
ibb_wait(IbbSoftDev *ibb_sp, u_long arg) {
int dev_num = ibb_sp->dev_num;
uint32_t table_index = (uint32_t) arg;
u_long flags;
int wq_ret = 0;
START;
if (ibb_sp->ushared == NULL) {
return(EAGAIN);
}
if (ibb_sp->ushared->image_table_index > table_index) {
debug_out(("ibb_ioctl(%d): IBBWAIT already got index %d\n",
dev_num, ibb_sp->ushared->image_table_index));
return(0);
}
lock_ibb(ibb_sp, &flags, "IBBWAIT 0");
ibb_sp->flags |= kIoWaiting;
ibb_sp->wait_for = table_index;
unlock_ibb(ibb_sp, &flags, "IBBWAIT 0");
debug_out(("ibb_ioctl(%d): IBBWAIT wait for %u, %u\n",
dev_num, ibb_sp->wait_for, ibb_sp->ushared->image_table_index)
);
wq_ret = wait_event_interruptible(ibb_sp->wq,
(ibb_sp->ushared->image_table_index > table_index));
debug_out(("ibb_ioctl(%d): IBBWAIT got index %d\n",
dev_num,ibb_sp->wait_for));
lock_ibb(ibb_sp, &flags, "IBBWAIT 1");
ibb_sp->flags &= ~kIoWaiting;
unlock_ibb(ibb_sp, &flags, "IBBWAIT 1");
if (ibb_sp->wait_for == kIbbWakeup) {
debug_out(("ibb_ioctl(%d): IBBWAIT got Wakeup\n", dev_num));
}
else if (ibb_sp->ushared->image_table_index > ibb_sp->wait_for) {
debug_out(("ibb_ioctl(%d): IBBWAIT got index %d\n",
dev_num,ibb_sp->wait_for));
}
else {
if(wq_ret != 0) {
debug_out(("ibb_ioctl(%d): IBBWAIT signal intr\n",
dev_num));
} else {
debug_out(("ibb_ioctl(%d): IBBWAIT Weird cond.\n",
dev_num));
}
return(-1); /* !! there's been a problem */
}
END;
return(0);
}
int
ibb_ioctl(struct inode *inode, struct file *filp, u_int cmd, u_long arg)
{
IbbSoftDev *ibb_sp = filp->private_data;
int retval = 0;
u_long flags;
START;
if (ibb_sp == NULL) {
debug_out(("ibb_ioctl(%d): Soft Info Lost\n", ibb_sp->dev_num));
return(-EFAULT);
}
switch (cmd) {
case IBBWAIT:
debug_out(("ibb_ioctl(%d): cmd IBBWAIT arg %lu\n",
ibb_sp->dev_num, arg));
retval = ibb_wait(ibb_sp, arg);
break;
case IBBTST:
if (ibb_sp->image_table == NULL)
return 0;
debug_out(("ibb_ioctl(%d): table 0 %x \n",
ibb_sp->dev_num,ibb_sp->image_table[0]) );
debug_out(("ibb_ioctl(%d): table 1 %x \n",
ibb_sp->dev_num,ibb_sp->image_table[1]) );
break;
case IBBWAKEUP:
debug_out(("ibb_ioctl(%d): cmd IBBWAKEUP\n",
ibb_sp->dev_num));
retval = 0;
if (ibb_sp->flags & kIoWaiting) {
lock_ibb(ibb_sp, &flags, "IBBWAKEUP");
ibb_sp->wait_for = kIbbWakeup;
unlock_ibb(ibb_sp, &flags, "IBBWAKEUP");
wake_up_interruptible(&ibb_sp->wq);
}
break;
case IBBFBACOUNT:
debug_out(("ibb_ioctl(%d): cmd IBBFBACOUNT arg %lu\n",
ibb_sp->dev_num, arg) );
lock_ibb(ibb_sp, &flags, "IBBFBACOUNT");
*(ibb_sp->fbac_virt) = (uint32_t) arg;
unlock_ibb(ibb_sp, &flags, "IBBFBACOUNT");
debug_out(("ibb_ioctl(%d): set fb count to %u\n",
ibb_sp->dev_num,*(ibb_sp->fbac_virt)));
retval = 0;
break;
case IBBFSIZE:
debug_out(("ibb_ioctl(%d): cmd IBBFSIZE arg %lu\n",
ibb_sp->dev_num,arg));
lock_ibb(ibb_sp, &flags, "IBBFSIZE");
*(ibb_sp->fsize_virt) = (uint32_t)arg;
unlock_ibb(ibb_sp, &flags, "IBBFSIZE");
debug_out(("ibb_ioctl(%d): set frame size to %u\n",
ibb_sp->dev_num,*(ibb_sp->fsize_virt)));
break;
case IBBSIZE:
debug_out(("ibb_ioctl(%d): cmd is IBBSIZE: %d\n",
ibb_sp->dev_num, ishared.frame_buffer_size));
retval = put_user(ishared.frame_buffer_size, (u_long *)
arg);
break;
case IBBVERSION:
if (put_user(kIbbVersion, (u_long *) arg)) {
debug_out(("ibb_ioctl(%d): can't copy ver info %d\n",
ibb_sp->dev_num,(int)kIbbVersion)) ;
retval = -EFAULT;
}
debug_out(("ibb_ioctl(%d): Copied ver info %d\n",
ibb_sp->dev_num, (int)kIbbVersion));
break;
case IBBCLIBB_ID:
if (put_user(ibb_sp->clibb_id, (short *)arg)) {
debug_out(("ibb_ioctl(%d): can't copy CLIBB ID %d\n",
ibb_sp->dev_num,ibb_sp->clibb_id)) ;
retval = -EFAULT;
}
debug_out(("ibb_ioctl(%d): Copied CLIBB IDD %d\n",
ibb_sp->dev_num,ibb_sp->clibb_id));
break;
case IBBHEIGHTGO:
if (ibb_sp->clibb_id != kClibb_HSC) {
debug_out(("ibb_ioctl(%d): ERROR: No Height Sensor\n",
ibb_sp->dev_num) );
return(-EFAULT);
}
ibb_sp->height_inspection = 1;
debug_out(("ibb_ioctl(%d): Start Height Inspection %d\n",
ibb_sp->dev_num,ibb_sp->height_inspection));
break;
case IBBHEIGHTSTOP:
ibb_sp->height_inspection = 0;
debug_out(("ibb_ioctl(%d): Stop Height Inspection %d\n",
ibb_sp->dev_num,ibb_sp->height_inspection));
break;
default:
debug_out(("ibb_ioctl(%d): unknown case: %d\n",
ibb_sp->dev_num, cmd) );
return(-ENOTTY);
break;
}
END;
return(retval);
}
int
ibb_open(struct inode *inode, struct file *filep) {
int dev_num;
IbbSoftDev *ibb_sp;
int major = MAJOR(inode->i_rdev);
int minor = MINOR(inode->i_rdev);
START;
debug_out(("ibb_open: major %d minor %d\n", major, minor));
dev_num = find_ibb_soft_state(major);
if (dev_num < 0) {
debug_out(("ibb_open: dev_num %d failed\n", dev_num));
return(-1);
}
ibb_sp = IbbSoft[dev_num];
filep->private_data = ibb_sp;
debug_out(("ibb_open(%d): opened by %s pid %d PAGE_SIZE %#010lx\n",
dev_num,current->comm, current->pid, PAGE_SIZE));
END;
return(0);
}
int
ibb_close(struct inode *inode, struct file *filep) {
IbbSoftDev *ibb_sp = filep->private_data;
START;
debug_out(("ibb_close(%d): called\n", ibb_sp->dev_num));
END;
return(0);
}
/*
* According to what I was told on the mailing lists, ClearPageReserved
is
* now depricated and shouldn't be needed but we can leave it for now
for
* backwards compatability (until when???) but also that you should
never,
* ever access _count (in atomic_set(&page->_count) directly so it's
commented
* out becuase I don't really know why it's there????
*
* BDM - 04/18/2006
*/
static void
free_ibb_usr_shared(IbbSoftDev *ibb_sp)
{
struct page *page;
u_long virt_addr;
u_long ushared_addr = (u_long)ibb_sp->ushared;
START;
for (virt_addr = ushared_addr;
virt_addr < ushared_addr + PAGE_ALIGN(IBB_SHARED_SIZE);
virt_addr += PAGE_SIZE)
{
page = virt_to_page(virt_addr);
ClearPageReserved(page);
// atomic_set(&page->_count, 1);
vfree((void *)virt_addr);
}
if (ibb_sp->ushared)
ibb_sp->ushared = NULL;
END;
}
static int
alloc_ibb_usr_shared(IbbSoftDev *ibb_sp) {
u_long virt_addr;
u_long ushared_addr;
int order = 0;
/*
* From Linux Device Drivers - memory that is going to
* be mmaped must be PAGE_SIZE grained. Since we do mmap
* ushared to user space, we need to allocated it in
* PAGE_SIZE chunks.
*/
int size = PAGE_ALIGN(IBB_SHARED_SIZE);
START;
debug_out(("ibb::size is %d\n", size));
debug_out(("ibb::order is %d\n", order));
do {
debug_out(("ibb::size is %d\n", size));
debug_out(("ibb::order is %d\n", order));
order++;
} while (size > (PAGE_SIZE * (1 << order)));
ibb_sp->ushared = (IbbUserShared *) __get_free_pages(GFP_KERNEL,
order);
// ibb_sp->ushared = (IbbUserShared *) vmalloc(4096 * 1024);
// ibb_sp->ushared = (IbbUserShared *) vmalloc(size);
if (ibb_sp->ushared == NULL) {
debug_out(("alloc_ibb_usr_shared(%d): no memory.\n",
ibb_sp->dev_num));
return(-1);
}
ushared_addr = (u_long) ibb_sp->ushared;
/* reserve all pages to make them remapable */
for (virt_addr = ushared_addr;
virt_addr < ushared_addr + size;
virt_addr += PAGE_SIZE)
{
SetPageReserved(virt_to_page(virt_addr));
}
ibb_sp->ushared->badsnap = 0;
ibb_sp->ushared->image_table_index = 0;
END;
return(0);
}
/*
* According to what I was told on the mailing lists, ClearPageReserved
is
* now depricated and shouldn't be needed but we can leave it for now
for
* backwards compatability (until when???) but also that you should
never,
* ever access _count (in atomic_set(&page->_count) directly so it's
commented
* out becuase I don't really know why it's there????
*
* BDM - 04/18/2006
*/
static void
free_ibb_image_table_mem(IbbSoftDev *ibb_sp) {
uint32_t *virt_addr;
struct page *page;
START;
debug_out(("free_ibb_image_table_mem(%d): Free size %d.\n",
ibb_sp->dev_num, ibb_sp->image_table_size));
/* unreserve all pages */
for (virt_addr = ibb_sp->image_table;
virt_addr < ibb_sp->image_table + ibb_sp->image_table_size;
virt_addr += PAGE_SIZE)
{
page = virt_to_page(virt_addr);
ClearPageReserved(page);
// atomic_set(&page->_count, 1);
free_page((u_long)virt_addr);
}
if (ibb_sp->image_table) {
ibb_sp->image_table = NULL;
}
ibb_sp->image_table_size = 0;
debug_out(("static void free_ibb_image_table_mem - DONE!\n"));
END;
return;
}
static int
alloc_ibb_image_table_mem(IbbSoftDev *ibb_sp, int size) {
int order = 0;
uint32_t *virt_addr;
u_int table_size = PAGE_ALIGN(size);
START;
debug_out(("alloc_ibb_image_table_mem(%d): Alloc size %d.\n",
ibb_sp->dev_num,table_size));
/*
* get a memory area with kmalloc and aligned it to a page. This
area
* will be physically contigous
*/
while (size > (PAGE_SIZE * (1 << order))) {
order++;
}
ibb_sp->image_table = (uint32_t *) __get_free_pages(GFP_KERNEL,
order);
// ibb_sp->ushared = (IbbUserShared *) vmalloc(4096 * 1024);
// ibb_sp->image_table = vmalloc(size);
if (ibb_sp->image_table == NULL) {
debug_out(("alloc_ibb_image_table_mem(%d): out of memory.\n",
ibb_sp->dev_num));
ibb_sp->image_table_size = 0;
return(-1);
}
/* reserve all pages to make them remapable */
for (virt_addr = ibb_sp->image_table;
virt_addr < ibb_sp->image_table + table_size;
virt_addr += PAGE_SIZE)
{
SetPageReserved(virt_to_page(virt_addr));
}
ibb_sp->image_table_size = table_size;
debug_out(("static int alloc_ibb_image_table_mem - DONE!\n"));
END;
return(0);
}
static int
ibb_map_one(IbbSoftDev *ibb_sp, u_long phys, u_long size, uint32_t
**virt, const char *what)
{
struct resource *res;
START;
if ((res = request_mem_region(phys, size, ibb_sp->devname)) == NULL)
{
debug_out(( "ibb_map_one(%d): can't allocate %s at %010lx
%#010lx %s\n",
ibb_sp->dev_num, what, phys, size, ibb_sp->devname));
return(-1);
}
else {
*virt = ioremap_nocache(phys, size);
if (!virt) {
debug_out(("ibb_map_one(%d): Error in ioremap\n",
ibb_sp->dev_num));
release_mem_region(phys, size);
return(-1);
}
}
debug_out(("ibb_map_one(%d): Successful map %s\n",
ibb_sp->dev_num,what));
END;
return(0);
}
static void
free_all_mappings(IbbSoftDev *ibb_sp)
{
START;
if (ibb_sp->creg_virt != NULL) {
iounmap(ibb_sp->creg_virt);
ibb_sp->creg_virt = NULL;
}
/* we can call release_mem_region() without checking anything -
* if the region hasn't been requested, the function will
* just exit with an error message.
* (unlike iounmap())
*/
release_mem_region(ibb_sp->creg_phys, ibb_sp->creg_size);
if (ibb_sp->height_virt != NULL) {
iounmap(ibb_sp->height_virt);
ibb_sp->height_virt = NULL;
}
release_mem_region(ibb_sp->height_phys, ibb_sp->height_size);
if (ibb_sp->csram_virt != NULL) {
iounmap(ibb_sp->csram_virt);
ibb_sp->csram_virt = NULL;
}
release_mem_region(ibb_sp->csram_phys, ibb_sp->csram_size);
if (ibb_sp->rsram_virt != NULL) {
iounmap(ibb_sp->rsram_virt);
ibb_sp->rsram_virt = NULL;
}
release_mem_region(ibb_sp->rsram_phys, ibb_sp->rsram_size);
if (ibb_sp->fbac_virt != NULL) {
iounmap(ibb_sp->fbac_virt);
ibb_sp->fbac_virt = NULL;
}
release_mem_region(ibb_sp->fbac_phys, ibb_sp->fbac_size);
if (ibb_sp->camdelay_virt != NULL) {
iounmap(ibb_sp->camdelay_virt);
ibb_sp->camdelay_virt = NULL;
}
release_mem_region(ibb_sp->camdelay_phys, ibb_sp->camdelay_size);
if (ibb_sp->fsize_virt != NULL) {
iounmap(ibb_sp->fsize_virt);
ibb_sp->fsize_virt = NULL;
}
release_mem_region(ibb_sp->fsize_phys, ibb_sp->fsize_size);
if (ibb_sp->extime_virt != NULL) {
iounmap(ibb_sp->extime_virt);
ibb_sp->extime_virt = NULL;
}
release_mem_region(ibb_sp->extime_phys, ibb_sp->extime_size);
if (ibb_sp->plsram_virt != NULL) {
iounmap(ibb_sp->plsram_virt);
ibb_sp->plsram_virt = NULL;
}
release_mem_region(ibb_sp->plsram_phys, ibb_sp->plsram_size);
if (ibb_sp->fb0_virt != NULL) {
iounmap(ibb_sp->fb0_virt);
ibb_sp->fb0_virt = NULL;
}
release_mem_region(ibb_sp->fb0_phys, ibb_sp->fb0_size);
if (ibb_sp->fb1_virt != NULL) {
iounmap(ibb_sp->fb1_virt);
ibb_sp->fb1_virt = NULL;
}
release_mem_region(ibb_sp->fb1_phys, ibb_sp->fb1_size);
if (ibb_sp->image_table != NULL) {
free_ibb_image_table_mem(ibb_sp);
}
if (ibb_sp->ushared != NULL) {
free_ibb_usr_shared(ibb_sp);
}
END;
return;
}
static int
ibb_map_frame_buffer(IbbSoftDev *ibb_sp, u_long phys, ulong
*size,uint32_t **virt, const char *what) {
char whatsize[100];
uint32_t *check_addr;
long check;
START;
sprintf(whatsize, "%s 64", what);
*size = IBB_FB_64_MG;
if (ibb_map_one(ibb_sp, phys, *size, virt, whatsize) < 0) {
return(-1);
}
check = MAG_FB_NUMBER;
check_addr = *virt;
writel(check, check_addr);
debug_out(("ibb_map_frame_buffer(%d): %s put %lX at addr %p\n",
ibb_sp->dev_num, whatsize, check, check_addr));
check = readl(check_addr);
debug_out(("ibb_map_frame_buffer(%d): %s read %lX at addr %p\n",
ibb_sp->dev_num, whatsize, check, check_addr));
check_addr = (*virt) + (IBB_FB_32_MG / 4);
check = readl(check_addr);
debug_out(("ibb_map_frame_buffer(%d): %s read %lX at addr %p\n",
ibb_sp->dev_num, whatsize, check, check_addr));
if (check == MAG_FB_NUMBER) {
/* we only have 32 MB, but we've mapped 64 - try again */
iounmap(*virt);
(*virt) = NULL;
release_mem_region(phys, *size);
sprintf(whatsize, "%s 32", what);
*size = IBB_FB_32_MG;
if (ibb_map_one(ibb_sp, phys, *size, virt, whatsize) < 0) {
return(-1);
}
ishared.frame_buffer_size = IBB_FB_32_MG;
}
END;
return(0);
}
static int
ibb_do_all_mappings(IbbSoftDev *ibb_sp)
{
START;
/*
* Initialize here so we can call free_all_mappings without
* freeing unallocated mem
*/
ibb_sp->creg_virt = NULL;
ibb_sp->height_virt = NULL;
ibb_sp->csram_virt = NULL;
ibb_sp->rsram_virt = NULL;
ibb_sp->fbac_virt = NULL;
ibb_sp->camdelay_virt = NULL;
ibb_sp->fsize_virt = NULL;
ibb_sp->extime_virt = NULL;
ibb_sp->plsram_virt = NULL;
ibb_sp->fb0_virt = NULL;
ibb_sp->fb1_virt = NULL;
ibb_sp->image_table = NULL;
ibb_sp->image_table_size = 0;
/* Map Control Register */
ibb_sp->creg_phys = ibb_sp->iobase + IBB_CONTROL_OFF;
ibb_sp->creg_size = IBB_CONTROL_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->creg_phys,
ibb_sp->creg_size,
&ibb_sp->creg_virt,
"Control Register") < 0)
{
return(-1);
}
/* Map Height Sensor Register */
ibb_sp->height_phys = ibb_sp->iobase + IBB_HEIGHT_OFF;
ibb_sp->height_size = IBB_HEIGHT_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->height_phys,
ibb_sp->height_size,
&ibb_sp->height_virt,
"Height Sensor") < 0)
{
return(-1);
}
/* Map Col Sram */
ibb_sp->csram_phys = ibb_sp->iobase + IBB_CSRAM_OFF;
ibb_sp->csram_size = IBB_CSRAM_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->csram_phys,
ibb_sp->csram_size,
&ibb_sp->csram_virt,
"Col Sram") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* Map Row Sram */
ibb_sp->rsram_phys = ibb_sp->iobase + IBB_RSRAM_OFF;
ibb_sp->rsram_size = IBB_RSRAM_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->rsram_phys,
ibb_sp->rsram_size,
&ibb_sp->rsram_virt,
"Row Sram") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map FB Address Counter */
ibb_sp->fbac_phys = ibb_sp->iobase + IBB_FBACOUNT_OFF;
ibb_sp->fbac_size = IBB_FBACOUNT_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->fbac_phys,
ibb_sp->fbac_size,
&ibb_sp->fbac_virt,
"FB Addr Count") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map Camera Delay Register */
ibb_sp->camdelay_phys = ibb_sp->iobase + IBB_CAMDELAY_OFF;
ibb_sp->camdelay_size = IBB_CAMDELAY_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->camdelay_phys,
ibb_sp->camdelay_size,
&ibb_sp->camdelay_virt,
"Cameral Delay Reg") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map Frame Size Register */
ibb_sp->fsize_phys = ibb_sp->iobase + IBB_FSIZE_OFF;
ibb_sp->fsize_size = IBB_FSIZE_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->fsize_phys,
ibb_sp->fsize_size,
&ibb_sp->fsize_virt,
"Frame Size Reg") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map Exposure Time Register */
ibb_sp->extime_phys = ibb_sp->iobase + IBB_EXTIME_OFF;
ibb_sp->extime_size = IBB_EXTIME_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->extime_phys,
ibb_sp->extime_size,
&ibb_sp->extime_virt,
"Exposure Time Reg") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map Pixel LUT Sram */
ibb_sp->plsram_phys = ibb_sp->iobase + IBB_PLSRAM_OFF;
ibb_sp->plsram_size = IBB_PLSRAM_SIZE;
if (ibb_map_one(ibb_sp,
ibb_sp->plsram_phys,
ibb_sp->plsram_size,
&ibb_sp->plsram_virt,
"Pixel LUT Sram") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
/* map Frame Buffers - now it gets a little trickier */
ibb_sp->fb0_phys = ibb_sp->iobase + IBB_FB0_OFF;
ibb_sp->fb0_size = 0;
if (ibb_map_frame_buffer(ibb_sp,
ibb_sp->fb0_phys,
&ibb_sp->fb0_size,
&ibb_sp->fb0_virt,
"Frame Buffer 0") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
debug_out(("ibb_do_all_mappings(%d): fb0 Mapped Size %lx\n",
ibb_sp->dev_num,ibb_sp->fb0_size));
ibb_sp->fb1_phys = ibb_sp->iobase + IBB_FB1_OFF;
ibb_sp->fb1_size = 0;
if (ibb_map_frame_buffer(ibb_sp,
ibb_sp->fb1_phys,
&ibb_sp->fb1_size,
&ibb_sp->fb1_virt,
"Frame Buffer 1") < 0)
{
free_all_mappings(ibb_sp);
return(-1);
}
debug_out(("ibb_do_all_mappings(%d): fb1 Mapped Size %lx\n",
ibb_sp->dev_num,ibb_sp->fb1_size));
if (alloc_ibb_usr_shared(ibb_sp) < 0) {
free_all_mappings(ibb_sp);
return(-1);
}
debug_out(("ibb_do_all_mappings(%d): IbbUserShared %lx\n",
ibb_sp->dev_num, (long)IBB_SHARED_SIZE));
END;
return(0);
}
int
ibb_mmap(struct file *filep, struct vm_area_struct *vma) {
IbbSoftDev *ibb_sp = filep->private_data;
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT);
unsigned long page = (ibb_sp->iobase + offset) >> PAGE_SHIFT;
START;
if (offset > __pa(high_memory) || (filep->f_flags & O_SYNC)) {
vma->vm_flags |= VM_IO;
}
vma->vm_flags |= VM_RESERVED;
debug_out((
"mmap(%d): st %#010lx off %#010lx(%#010lx) sz %#010lx (end
%#010lx)\n",
ibb_sp->dev_num, vma->vm_start, ibb_sp->iobase + offset,
offset, (vma->vm_end - vma->vm_start), vma->vm_end));
debug_out(("ibb_mmap(%d): opened by %s pid %d\n",
ibb_sp->dev_num, current->comm, current->pid));
if (offset == IBB_IMAGE_ADDR) {
debug_out(("IBB_IMAGE_ADDR\n"));
if (ibb_sp->image_table != NULL && size >
ibb_sp->image_table_size) {
debug_out(("ibb_mmap(%d): Free Image Table\n",
ibb_sp->dev_num));
free_ibb_image_table_mem(ibb_sp);
}
if (ibb_sp->image_table == NULL) {
debug_out(("ibb_mmap(%d): Alloc New Image Table\n",
ibb_sp->dev_num));
alloc_ibb_image_table_mem(ibb_sp, (vma->vm_end -
vma->vm_start));
}
if (ibb_sp->image_table != NULL && size <=
ibb_sp->image_table_size) {
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
}
debug_out(("IBB_IMAGE_ADDR - DONE!\n"));
}
else if (offset == IBB_SHARED_ADDR) {
debug_out(("IBB_SHARED_ADDR\n"));
if (ibb_sp->ushared != NULL && size <=
PAGE_ALIGN(IBB_SHARED_SIZE)) {
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("ibb_mmap(%d): \
ushared remap: ibb_sp->ushared: %lx vma->vm_start:
%lx\n",
ibb_sp->dev_num,
(u_long)ibb_sp->ushared,
(u_long)vma->vm_start) );
} else {
debug_out(("ibb_mmap(%d): ushared mmap failed\n",
ibb_sp->dev_num));
return(-EAGAIN);
}
debug_out(("IBB_SHARED_ADDR - DONE!\n"));
}
else if (offset == IBB_CONTROL_OFF && size == PAGE_SIZE) {
debug_out(("IBB_CONTROL_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_CONTROL_OFF - DONE!\n"));
}
else if (offset == IBB_CSRAM_OFF && size == IBB_CSRAM_SIZE) {
debug_out(("IBB_CSRAM_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_CSRAM_OFF - DONE!\n"));
}
else if (offset == IBB_RSRAM_OFF && size == IBB_RSRAM_SIZE) {
debug_out(("IBB_RSRAM_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_RSRAM_OFF - DONE!\n"));
}
else if (offset == IBB_FBACOUNT_OFF && size == PAGE_SIZE) {
debug_out(("IBB_FBACOUNT_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_FBACOUNT_OFF - DONE!\n"));
}
else if (offset == IBB_CAMDELAY_OFF && size == PAGE_SIZE) {
debug_out(("IBB_CAMDELAY_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_CAMDELAY_OFF - DONE!\n"));
}
else if (offset == IBB_FSIZE_OFF && size == PAGE_SIZE) {
debug_out(("IBB_FSIZE_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_FSIZE_OFF - DONE!\n"));
}
else if (offset == IBB_EXTIME_OFF && size == PAGE_SIZE) {
debug_out(("IBB_EXTIME_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_EXTIME_OFF - DONE!\n"));
}
else if (offset == IBB_PLSRAM_OFF && size == IBB_PLSRAM_SIZE) {
debug_out(("IBB_PLSRAM_OFF\n"));
debug_out(("ibb_mmap(%d): PLUT Sram %lx %lx\n",
ibb_sp->dev_num, (long)offset, size));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_PLSRAM_OFF - DONE!\n"));
}
else if (offset == IBB_FB0_OFF
&& (size == IBB_FB_32_MG
|| size == IBB_FB_64_MG))
{
debug_out(("IBB_FB0_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_FB0_OFF - DONE!\n"));
}
else if (offset == IBB_FB1_OFF
&& (size == IBB_FB_32_MG
|| size == IBB_FB_64_MG))
{
debug_out(("IBB_FB1_OFF\n"));
while (size > PAGE_SIZE) {
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
return(-EAGAIN);
}
start += PAGE_SIZE;
if (size > PAGE_SIZE) {
size -= PAGE_SIZE;
} else {
size = 0;
}
}
debug_out(("IBB_FB1_OFF - DONE!\n"));
}
else {
debug_out(("IBB_???_OFFSET --- WE'RE BROKEN!!!\n"));
return(-EAGAIN);
}
END;
return(0);
}
struct file_operations ibb_fops = {
read: ibb_read,
write: ibb_write,
ioctl: ibb_ioctl,
mmap: ibb_mmap,
open: ibb_open,
release: ibb_close,
};
static int __initdata
ibb_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) {
IbbSoftDev *ibb_sp;
int i = 0;
int dev_num;
int ibb_major;
int result;
int res;
u8 rev_id = 0;
u16 device_id;
uint16_t subsystem_id = 0;
char revid = ' ';
START;
if (pci_enable_device(pdev))
return(-ENODEV);
result = 0;
debug_out((
"ibb_probe: IBB Device 0x%08x has been found @bus %d dev %d func
%d\n",
pdev->device,
pdev->bus->number,
PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn)));
/* alloc our per-device data */
dev_num = alloc_ibb_soft_state();
if (dev_num < 0)
return(-ENOMEM);
/* initialize data */
memset(IbbSoft[dev_num], 0, sizeof(IbbSoft[dev_num]));
ibb_sp = IbbSoft[dev_num];
sprintf(ibb_sp->devname, "ibb%d", dev_num);
spin_lock_init(&ibb_sp->mutex);
ibb_sp->dev_num = dev_num;
ibb_sp->pdev = pdev;
ibb_sp->height_inspection = 0;
sema_init(&ibb_sp->sem, 1);
pci_set_drvdata(pdev, ibb_sp); /* we'll need this in remove: */
debug_out(("ibb_probe: device %d\n", dev_num));
#define REQUESTMEM
#ifdef REQUESTMEM
for (i = 0; i < kMaxIbbs; i++) {
ishared.dev_instance[i] = -1;
}
/* start with the max size */
ishared.frame_buffer_size = IBB_FB_64_MG;
/*
* map the card memory areas into kernel space
* and store the address in our IbbDev info
*/
ibb_sp->iobase = pci_resource_start(pdev, 0);
ibb_sp->iosize = pci_resource_len(pdev, 0);
if (ibb_do_all_mappings(ibb_sp) < 0) {
free_ibb_soft_state(ibb_sp->dev_num);
return(-ENODEV);
}
#endif
ibb_major = 0;
result = register_chrdev(ibb_major, ibb_sp->devname, &ibb_fops);
if (result < 0) {
debug_out(("ibb_probe(%d): can't get register driver\n",
dev_num));
free_all_mappings(ibb_sp);
free_ibb_soft_state(ibb_sp->dev_num);
return(-EBUSY);
}
if (ibb_major == 0) {
ibb_major = result; /* dynamic */
}
debug_out(("ibb_probe(%d): got major %d\n",dev_num,ibb_major));
ibb_sp->ibb_major = ibb_major;
pci_read_config_word(pdev, 2, &device_id);
pci_read_config_byte(pdev, 8, &rev_id);
pci_read_config_word(pdev, 46, &subsystem_id);
ibb_sp->clibb_id = subsystem_id;
if (rev_id > 0 && rev_id < 27) {
rev_id += 0x40; /* translate to ascii (A = 1, B = 2,
etc) */
revid = rev_id;
}
if (!pdev->irq) {
debug_out(("ibb_probe_module(%d): can't get int number\n",
dev_num));
free_all_mappings(ibb_sp);
free_ibb_soft_state(ibb_sp->dev_num);
return(-ENODEV);
}
ibb_sp->myint = pdev->irq;
res = request_irq(ibb_sp->myint,
ibb_intr,
SA_SHIRQ,ibb_sp->devname,
ibb_sp);
if (res != 0) {
debug_out(("ibb_open(%d): irq request %d failed\n", dev_num,
res));
return(-1);
}
init_waitqueue_head(&ibb_sp->wq);
if (ibb_sp->clibb_id == kIbbId) {
debug_out(("MVP Image Buffer Board: ibb%d, %X.%c, Int: %d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
else if (ibb_sp->clibb_id == kClibbSingle) {
debug_out(("MVP Camera Link Single IBB: ibb%d, %X.%c, Int:
%d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
else if (ibb_sp->clibb_id == kClibbDualRow) {
debug_out(("MVP Camera Link DualRow IBB: ibb%d, %X.%c, Int:
%d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
else if (ibb_sp->clibb_id == kClibbDualCol) {
debug_out(("MVP CL DualCol IBB ibb%d, %X.%c, Int: %d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
else if (ibb_sp->clibb_id == kClibb_HSC) {
debug_out(("MVP HSC Camera Link IBB: ibb%d, %X.%c, Int: %d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
else {
debug_out(("MVP Unknown IBB: ibb%d, %X.%c, Int: %d\n",
dev_num,
device_id,
revid,
ibb_sp->myint));
}
/* store device id */
debug_out(("MVP driver(%d) %s\n", dev_num, ibb_c));
END;
return(result);
}
static void __exitdata
ibb_remove(struct pci_dev *pdev)
{
IbbSoftDev *ibb_sp = (IbbSoftDev *)pci_get_drvdata(pdev);
START;
if (ibb_sp == NULL) {
debug_out(("ibb_remove: Error: Null IBB Data in remove\n"));
return;
}
debug_out(("ibb_remove(%d):\n", ibb_sp->dev_num));
debug_out(("ibb_remove(%d): unregister drv %s\n",
ibb_sp->dev_num,
ibb_sp->devname));
if (ibb_sp) {
free_irq(ibb_sp->myint, (void *)ibb_sp);
debug_out(("ibb_remove(%d): free_irq myint%d\n",
ibb_sp->dev_num,
ibb_sp->myint));
ibb_sp->myint = 0;
}
unregister_chrdev(ibb_sp->ibb_major, ibb_sp->devname);
debug_out(("ibb_remove(%d): release memory\n", ibb_sp->dev_num));
free_all_mappings(ibb_sp);
free_ibb_soft_state(ibb_sp->dev_num);
END;
}
static struct pci_device_id ibb_id_table[] __devinitdata = {
{ 0x8f73, 0xb1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x8f73, 0xb2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x8f73, 0xb3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x8f73, 0xcb1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x8f73, 0xcb2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 } };
/*
* have _no idea_ why I'm calling this - find out!
*
* from /usr/inluclude/linux/module.h
* MODULE_DEVICE_TABLE exports information about devices
* currently supported by this module. A device type, such as PCI,
* is a C-like identifier passed as the first arg to this macro.
* The second macro arg is the variable containing the device
* information being made public.
*
* The following is a list of known device types (arg 1),
* and the C types which are to be passed as arg 2.
* pci - struct pci_device_id - List of PCI ids supported by this module
* isapnp - struct isapnp_device_id -
* List of ISA PnP ids supported by this module
* usb - struct usb_device_id - List of USB ids supported by this module
*
* still - ok so it exports it, who imports it and what do they
* do with it?
*/
MODULE_DEVICE_TABLE(pci, ibb_id_table);
struct pci_driver ibb_driver = {
name: "ibb",
id_table: ibb_id_table,
probe: ibb_probe,
remove: ibb_remove,
};
int __init
ibb_init_module(void)
{
START;
init_ibb_soft_state();
END;
return(pci_module_init(&ibb_driver));
}
void __exit
ibb_cleanup_module(void)
{
START;
pci_unregister_driver(&ibb_driver);
END;
}
static inline void
set_next_fb(uint32_t *control_regp, uint32_t next_snap, int instance,
int temp_debug) {
uint32_t next_fb = (next_snap & IAT_FB_MASK) >> IAT_FB_SHIFT;
START;
if (next_fb == 0) {
*(control_regp) = *(control_regp) | ICR_FB0_ENABL;
*(control_regp) = *(control_regp) & ~ICR_FB1_ENABL;
}
else if (next_fb == 1) {
*(control_regp) = *(control_regp) | ICR_FB1_ENABL;
*(control_regp) = *(control_regp) & ~ICR_FB0_ENABL;
}
debug_out(("ibb_intr(%d): set fb %d %x\n",
instance,
next_fb,
*(control_regp)));
END;
}
static inline void
set_next_camera(uint32_t *control_regp, uint32_t next_snap, int
instance, int temp_debug) {
uint32_t next_camera;
START;
/* first, clear the previous camera settings */
*(control_regp) &= ICR_CLEARCAM;
next_camera = (next_snap & IAT_CAMERA_MASK) >> IAT_CAMERA_SHIFT;
if (next_camera < 0 || next_camera > 7) {
return;
}
*(control_regp) |= (next_camera << ICR_CAMERA_SHIFT);
debug_out(("ibb_intr(%d): set camera %d reg %x\n",
instance,
next_camera,
*(control_regp)) );
END;
}
static inline void
set_next_address(IbbSoftDev *ibb_p, uint32_t ibb_control_reg, uint32_t
next_snap, int instance, int temp_debug) {
uint32_t next_address = (next_snap & IAT_ADDR_MASK);
START;
debug_out(("ibb_intr(%d): got address 0x%x set 0x%x\n",
instance,
*(ibb_p->fbac_virt),
next_address));
*(ibb_p->fbac_virt) = next_address;
END;
}
static inline void
check_intr_delay(IbbSoftDev *ibb_p)
{
START;
#ifdef TESTCAMDELAY
hrtime_t snap_ndelay;
hrtime_t ibb_ntimestamp;
/* this may be useful but only in fly mode */
ibb_ntimestamp = gethrtime();
debug_out(("ibb_intr: ibbtime %llu\n",ibb_ntimestamp / 1000000));
debug_out(("ibb_intr: rtctime %llu\n", ishared.rtc_ntimestamp));
if (ibb_ntimestamp < ishared.rtc_ntimestamp) {
debug_out(("ibb_intr: Bad value %llu for rtc intr\n",
ishared.rtc_ntimestamp));
}
snap_ndelay = ibb_ntimestamp - ishared.rtc_ntimestamp;
if (snap_ndelay < kMinSnapDelay) {
debug_out(("ibb_intr: grab snap delay %lld too short\n",
snap_ndelay / 1000000));
ibb_p->ushared->badsnap = kIbbShortSnap;
}
else if (snap_ndelay > kMaxSnapDelay) {
debug_out(("ibb_intr: grab snap delay %lld too long\n",
snap_ndelay / 1000000));
ibb_p->ushared->badsnap = kIbbLongSnap;
}
#endif
END;
return;
}
irqreturn_t
ibb_intr(int irq, void *dev_id, struct pt_regs *regs) {
IbbSoftDev *ibb_sp = dev_id;
uint32_t creg_val;
uint32_t intr_set;
uint32_t last_snap;
uint32_t next_snap;
int instance;
int temp_debug = 100;
u_long flags;
START;
if (ibb_sp == NULL) {
debug_out(("ERROR: ibb_intr: ibb_sp = NULL\n"));
return(IRQ_NONE);
}
lock_ibb(ibb_sp, &flags, "ibb_intr");
instance = ibb_sp->dev_num;
creg_val = *ibb_sp->creg_virt;
if (!(creg_val & ICR_INTR_PENDING)) {
debug_out(("ibb_intr(%d): Not mine\n", ibb_sp->dev_num));
unlock_ibb(ibb_sp, &flags, "ibb_intr Error");
return(IRQ_NONE);
}
if (creg_val & ICR_CAM_FAIL) {
debug_out(("ibb_intr(%d): Camera Failure\n",ibb_sp->dev_num));
}
/* RESET INTR set ICR_INTR_CLEAR hi and remove software intrs*/
intr_set =
(ICR_INTR_CLEAR | creg_val | ICR_CLR_CAM_FAIL)
& ~(ICR_SOFT_IMAGE | ICR_SIM_FIRE);
*ibb_sp->creg_virt = intr_set;
if (ibb_sp->ushared != NULL && ibb_sp->image_table != NULL) {
ibb_sp->ushared->badsnap = 0;
last_snap =
ibb_sp->image_table[ibb_sp->ushared->image_table_index];
if (ibb_sp->height_inspection) {
uint32_t *address_start;
uint32_t *last_frame;
uint32_t height_data;
uint32_t last_address;
uint32_t last_fb = (last_snap & IAT_FB_MASK) >>
IAT_FB_SHIFT;
if (last_fb == 0) {
address_start = ibb_sp->fb0_virt;
}
else {
address_start = ibb_sp->fb1_virt;
}
last_address = last_snap & IAT_ADDR_MASK;
last_frame = address_start + last_address;
height_data = *(ibb_sp->height_virt);
height_data <<= 16;
*(last_frame) = height_data;
}
last_snap = last_snap | IAT_SNAP_DONE;
ibb_sp->image_table[ibb_sp->ushared->image_table_index] =
last_snap;
ibb_sp->ushared->image_table_index++;
debug_out(("ibb_intr(%d): set index %d\n",
ibb_sp->dev_num,
ibb_sp->ushared->image_table_index));
next_snap =
ibb_sp->image_table[ibb_sp->ushared->image_table_index];
debug_out(("ibb_intr(%d): got next entry %d %x\n",instance,
ibb_sp->ushared->image_table_index,
next_snap));
creg_val = *ibb_sp->creg_virt;
debug_out(("ibb_intr(%d): set %x intr %x\n",
ibb_sp->dev_num,
intr_set,
creg_val));
set_next_fb(ibb_sp->creg_virt, next_snap, instance, temp_debug);
set_next_camera(ibb_sp->creg_virt, next_snap, instance,
temp_debug);
set_next_address(ibb_sp, creg_val, next_snap, instance,
temp_debug);
debug_out(("ibb_intr(%d): fbacount 0x%x\n",
instance,
*(ibb_sp->fbac_virt)));
if (ibb_sp->flags & kIoWaiting) {
debug_out(("ibb_intr(%d): waiting for ind %d got %d\n",
instance,
ibb_sp->wait_for,
ibb_sp->ushared->image_table_index));
if (ibb_sp->ushared->image_table_index > ibb_sp->wait_for) {
debug_out(("ibb_intr(%d): wake up wait queue\n",
ibb_sp->dev_num));
wake_up_interruptible(&ibb_sp->wq);
}
}
check_intr_delay(ibb_sp);
}
barrier();
*ibb_sp->creg_virt =
(~(ICR_INTR_CLEAR|ICR_CLR_CAM_FAIL) & *ibb_sp->creg_virt);
unlock_ibb(ibb_sp, &flags, "ibb_intr");
debug_out(("irqreturn_t ibb_intr - DONE!\n"));
END;
return(IRQ_HANDLED);
}
void
ibb_rtc_wakeup(void)
{
int i;
u_long flags;
START;
for (i = 0; i < kMaxIbbs; i++) {
if (IbbSoft[i] != NULL) {
lock_ibb(IbbSoft[i], &flags, "ibb_rtc_wakeup");
IbbSoft[i]->wait_for = kIbbWakeup;
IbbSoft[i]->ushared->image_table_index =
IbbSoft[i]->wait_for + 1;
unlock_ibb(IbbSoft[i], &flags, "ibb_rtc_wakeup");
wake_up_interruptible(&IbbSoft[i]->wq);
}
}
END;
}
module_init(ibb_init_module);
module_exit(ibb_cleanup_module);
:b!
Brian D. McGrew { [email protected] || [email protected] }
--
> This is a test. This is only a test!
Had this been an actual emergency, you would have been
told to cancel this test and seek professional assistance!
-----Original Message-----
From: Arjan van de Ven [mailto:[email protected]]
Sent: Thursday, May 18, 2006 6:51 PM
To: Brian D. McGrew
Cc: [email protected]
Subject: Re: Invalid module format?
On Thu, 2006-05-18 at 07:01 -0700, Brian D. McGrew wrote:
> I have two device drivers for two separate PCI cards.
>
> Using the 2.6.15.6 I can compile and insert both of these drivers.
>
> I copy my sources to my 2.6.16.16 tree and recompile them. One driver
> inserts just fine (and works) and the other gives me this:
>
> FATAL: Error inserting ibb
> (/lib/modules/2.6.16.16/kernel/drivers/mvp/ibb.ko): Invalid module
> format
>
> The same source file between both kernels and I get no errors at
compile
> time.
you forgot to
1) look into dmesg and give us the information that gets printed there
when modprobe returns this error
2) point to the source of the driver
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]