Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750956AbWESRLw (ORCPT ); Fri, 19 May 2006 13:11:52 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751377AbWESRLw (ORCPT ); Fri, 19 May 2006 13:11:52 -0400 Received: from mail.visionpro.com ([63.91.95.13]:23083 "EHLO chicken.machinevisionproducts.com") by vger.kernel.org with ESMTP id S1750956AbWESRLu convert rfc822-to-8bit (ORCPT ); Fri, 19 May 2006 13:11:50 -0400 X-MimeOLE: Produced By Microsoft Exchange V6.5.7226.0 Content-class: urn:content-classes:message MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8BIT Subject: RE: Invalid module format? Date: Fri, 19 May 2006 10:11:48 -0700 Message-ID: <14CFC56C96D8554AA0B8969DB825FEA0012B3262@chicken.machinevisionproducts.com> X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: RE: Invalid module format? Thread-Index: AcZ65rr4eAsVBnaZQF6WxX7oEVROvwAf3q+wAABE2vA= From: "Brian D. McGrew" To: Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 75301 Lines: 3361 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 /* ioremap */ #include /* put_user */ #include /* access CONFIG_PCI macro */ #include #include /* request/free_irq */ #include /* memory mapping */ #include #include #include /* kmalloc() */ #include #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 #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 #include #include #include #include #include #include #include #include #include #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/