/* * main.c */ #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #include #include #include #include #include #include #include #include #include #include "hrt.h" #ifdef KERNEL_2_6 #include #endif /* */ /* fops */ int hrt_major_num; int hrt_open (struct inode *inode, struct file *file); int hrt_release(struct inode *inode, struct file *file); int hrt_read (struct file *file, char *buf, size_t count, loff_t * ppos); static int hrt_mmap (struct file *file, struct vm_area_struct *vma); void hrt_cleanup_module(void); EXPORT_SYMBOL(hrt_open); EXPORT_SYMBOL(hrt_release); EXPORT_SYMBOL(hrt_read); static struct file_operations hrt_fops = { .owner = THIS_MODULE, .open = hrt_open, .release = hrt_release, .read = hrt_read, .ioctl = hrt_ioctl, .mmap = hrt_mmap, }; /* * declare statics in hrt_types.h */ /* defined but not used */ int hrt_num_devices = 0; hrt_dev_t hrt_devices[HRT_MAX_DEVICES]; static int major_number = 82; hrt_parm(major_number, "i", int, 0); /* * functions */ int hrt_open(struct inode *inode, struct file *file) { hrt_dev_t* dev; unsigned int minor; #ifdef KERNEL_2_6 minor = iminor(inode); printk("<1>hrt minor is %d\n", minor); #else minor = MINOR(inode->i_rdev); #endif if (minor >= HRT_MAX_DEVICES) return -ENODEV; printk("<1>hrt_device addr = %X\n", (unsigned long)hrt_devices); dev = hrt_devices + minor; printk("<1>dev addr = %X\n", (unsigned long)dev); if (dev->valid == 0) return -ENODEV; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; printk("<1>hrt_setting private data\n"); file->private_data = (void*)dev; printk("<1>hrt checking in_use\n"); if (dev->in_use) { printk("<1>hrt is in_use\n"); up(&dev->sem); return -EBUSY; } else dev->in_use = 1; printk("<1>hrt installing interrupt\n"); hrt_install_interrupt(dev); up(&dev->sem); #ifndef KERNEL_2_6 MOD_INC_USE_COUNT; #endif return 0; } int hrt_release(struct inode *inode, struct file *file) { hrt_dev_t* dev = file->private_data; if (dev->valid == 0) return -ENODEV; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; dev->in_use = 0; hrt_remove_interrupt(dev); up(&dev->sem); #ifndef KERNEL_2_6 MOD_DEC_USE_COUNT; #endif return 0; } int hrt_read(struct file *file, char *buf, size_t count, loff_t * ppos) { hrt_dev_t* dev = file->private_data; if (dev->valid == 0) return -ENODEV; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /* check to see if the dev is open */ if (!dev->in_use) { up(&dev->sem); return -ENODEV; } while (!dev->frame_ready) { up(&dev->sem); if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(dev->wait_queue, (dev->frame_ready))) return -ERESTARTSYS; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; } if (count > (HRT_MAX_FRAMESIZE)) count = HRT_MAX_FRAMESIZE; #ifdef DOUBLE_BUFFERING if (copy_to_user(buf, dev->frame_bufferr, count)) { #else if (copy_to_user(buf, dev->frame_buffer, count)) { #endif up(&dev->sem); return -EFAULT; } #ifdef HRT_DEBUG dev->debug_read_count++; #endif dev->frame_ready = 0; up(&dev->sem); return count; } static void hrt_vma_open(struct vm_area_struct *vma) { } static void hrt_vma_close(struct vm_area_struct *vma) { } static struct page *hrt_vma_nopage(struct vm_area_struct *vma, unsigned long address, #ifdef KERNEL_2_6 int *type) #else int write_access) #endif { hrt_dev_t *hrtdev = (hrt_dev_t *)(vma->vm_file->private_data); unsigned long offset = (address - vma->vm_start); struct page *p = (struct page *)NULL; if (!hrtdev) return 0; if (offset >= hrtdev->fb_size) return 0; #ifdef DOUBLE_BUFFERING return 0; #else p = vmalloc_to_page(hrtdev->frame_buffer + offset); #endif if (p != NULL) get_page(p); return p; } static struct vm_operations_struct hrt_vm_ops = { .open = hrt_vma_open, .close = hrt_vma_close, .nopage = hrt_vma_nopage }; #if !defined (pgprot_noncached) static inline pgprot_t pgprot_noncached(pgprot_t old_prot) { pgprot_t new_prot = old_prot; if (boot_cpu_data.x86 > 3) new_prot = __pgprot(pgprot_val(old_prot) | _PAGE_PCD | _PAGE_PWT); return new_prot; } #endif int hrt_mmap_direct(struct file *file, struct vm_area_struct *vma, unsigned long int_offs) { hrt_dev_t *hrtdev = (hrt_dev_t *)file->private_data; unsigned long start = (hrtdev->phys_addr); vma->vm_flags |= (VM_IO | VM_RESERVED); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* PCI memory, make it a PAGE address */ if (start > (unsigned long)__va(high_memory)) start >>= PAGE_SHIFT; if (remap_page_range( #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) vma, #endif vma->vm_start, start + int_offs, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; else return 0; } int hrt_mmap(struct file *file, struct vm_area_struct *vma) { hrt_dev_t *hrtdev = (hrt_dev_t *)file->private_data; unsigned long size = (vma->vm_end - vma->vm_start); if (hrtdev->valid == 0) return -ENODEV; if (down_interruptible(&hrtdev->sem)) return -ERESTARTSYS; if (vma->vm_pgoff == (HRT_MAGIC_SCANLINE_MMAP_OFFSET / PAGE_SIZE)) { /* requesting direct I/O on the board */ int ret = hrt_mmap_direct(file, vma, 0); hrt_printk("doing direct mmap(), size = %X\n", (unsigned)size); up(&hrtdev->sem); return ret; } if (vma->vm_pgoff == (HRT_MAGIC_REGISTER_MMAP_OFFSET / PAGE_SIZE)) { /* requesting direct I/O on the board */ int ret = hrt_mmap_direct(file, vma, 0x2000); hrt_printk("doing register direct mmap(), size = %X\n", (unsigned)size); up(&hrtdev->sem); return ret; } hrt_printk("doing normal mmap()\n"); if (size > hrtdev->fb_size) { up(&hrtdev->sem); return -EINVAL; } vma->vm_ops = &hrt_vm_ops; if (vma->vm_ops->open) vma->vm_ops->open(vma); up(&hrtdev->sem); return 0; } #ifdef HRT_DEBUG #define write_buf(args...) \ do { \ n = snprintf(buf, count, args); \ buf += n; \ count -= n; \ } while(0) int hrt_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0, n, i; int ips, tps, rps; char *org_buf = buf; if (hrt_devices[0].debug_count < 10) { ips = 0; tps = 0; rps = 0; } else { ips = (double)hrt_devices[0].debug_interrupt_count / ( (double)hrt_devices[0].debug_count / 10.0); tps = (double)hrt_devices[0].debug_timer_count / ((double)hrt_devices[0].debug_count / 10.0); rps = (double)hrt_devices[0].debug_read_count / ((double)hrt_devices[0].debug_count / 10.0); } /* dont excede count bytes when writing to buf */ /* just write to buf as a normal ptr to a file */ write_buf("dev HZ/10 int timer read int/s timer/s read/s\n"); for (i=0; i