📄 vfc_dev.c
字号:
/* * drivers/sbus/char/vfc_dev.c * * Driver for the Videopix Frame Grabber. * * In order to use the VFC you need to program the video controller * chip. This chip is the Phillips SAA9051. You need to call their * documentation ordering line to get the docs. * * There is very little documentation on the VFC itself. There is * some useful info that can be found in the manuals that come with * the card. I will hopefully write some better docs at a later date. * * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/smp_lock.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/io.h>#include <asm/system.h>#include <asm/sbus.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/uaccess.h>#define VFC_MAJOR (60)#if 0#define VFC_IOCTL_DEBUG#endif#include "vfc.h"#include <asm/vfc_ioctls.h>static struct file_operations vfc_fops;static devfs_handle_t devfs_handle; /* For the directory */struct vfc_dev **vfc_dev_lst;static char vfcstr[]="vfc";static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { 0x00, 0x64, 0x72, 0x52, 0x36, 0x18, 0xff, 0x20, 0xfc, 0x77, 0xe3, 0x50, 0x3e};void vfc_lock_device(struct vfc_dev *dev){ down(&dev->device_lock_sem);}void vfc_unlock_device(struct vfc_dev *dev){ up(&dev->device_lock_sem);}void vfc_captstat_reset(struct vfc_dev *dev) { dev->control_reg |= VFC_CONTROL_CAPTRESET; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg &= ~VFC_CONTROL_CAPTRESET; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg |= VFC_CONTROL_CAPTRESET; sbus_writel(dev->control_reg, &dev->regs->control);}void vfc_memptr_reset(struct vfc_dev *dev) { dev->control_reg |= VFC_CONTROL_MEMPTR; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg &= ~VFC_CONTROL_MEMPTR; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg |= VFC_CONTROL_MEMPTR; sbus_writel(dev->control_reg, &dev->regs->control);}int vfc_csr_init(struct vfc_dev *dev){ dev->control_reg = 0x80000000; sbus_writel(dev->control_reg, &dev->regs->control); udelay(200); dev->control_reg &= ~0x80000000; sbus_writel(dev->control_reg, &dev->regs->control); udelay(100); sbus_writel(0x0f000000, &dev->regs->i2c_magic2); vfc_memptr_reset(dev); dev->control_reg &= ~VFC_CONTROL_DIAGMODE; dev->control_reg &= ~VFC_CONTROL_CAPTURE; dev->control_reg |= 0x40000000; sbus_writel(dev->control_reg, &dev->regs->control); vfc_captstat_reset(dev); return 0;}int vfc_saa9051_init(struct vfc_dev *dev){ int i; for (i = 0; i < VFC_SAA9051_NR; i++) dev->saa9051_state_array[i] = saa9051_init_array[i]; vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR, dev->saa9051_state_array, VFC_SAA9051_NR); return 0;}int init_vfc_hw(struct vfc_dev *dev) { vfc_lock_device(dev); vfc_csr_init(dev); vfc_pcf8584_init(dev); vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic sun code above*/ vfc_saa9051_init(dev); vfc_unlock_device(dev); return 0; }int init_vfc_devstruct(struct vfc_dev *dev, int instance) { dev->instance=instance; init_MUTEX(&dev->device_lock_sem); dev->control_reg=0; init_waitqueue_head(&dev->poll_wait); dev->busy=0; return 0;}int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance){ char devname[8]; if(dev == NULL) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; } printk("Initializing vfc%d\n",instance); dev->regs = NULL; dev->regs = (volatile struct vfc_regs *) sbus_ioremap(&sdev->resource[0], 0, sizeof(struct vfc_regs), vfcstr); dev->which_io = sdev->reg_addrs[0].which_io; dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; if (dev->regs == NULL) return -EIO; printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); if (init_vfc_devstruct(dev, instance)) return -EINVAL; if (init_vfc_hw(dev)) return -EIO; sprintf (devname, "%d", instance); dev->de = devfs_register (devfs_handle, devname, DEVFS_FL_DEFAULT, VFC_MAJOR, instance, S_IFCHR | S_IRUSR | S_IWUSR, &vfc_fops, NULL); return 0;}struct vfc_dev *vfc_get_dev_ptr(int instance) { return vfc_dev_lst[instance];}static spinlock_t vfc_dev_lock = SPIN_LOCK_UNLOCKED;static int vfc_open(struct inode *inode, struct file *file) { struct vfc_dev *dev; spin_lock(&vfc_dev_lock); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); if (dev == NULL) { spin_unlock(&vfc_dev_lock); return -ENODEV; } if (dev->busy) { spin_unlock(&vfc_dev_lock); return -EBUSY; } dev->busy = 1; spin_unlock(&vfc_dev_lock); vfc_lock_device(dev); vfc_csr_init(dev); vfc_pcf8584_init(dev); vfc_init_i2c_bus(dev); vfc_saa9051_init(dev); vfc_memptr_reset(dev); vfc_captstat_reset(dev); vfc_unlock_device(dev); return 0;}static int vfc_release(struct inode *inode,struct file *file) { struct vfc_dev *dev; spin_lock(&vfc_dev_lock); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); if (!dev || !dev->busy) { spin_unlock(&vfc_dev_lock); return -EINVAL; } dev->busy = 0; spin_unlock(&vfc_dev_lock); return 0;}static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) { struct vfc_debug_inout inout; unsigned char *buffer; if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch(cmd) { case VFC_I2C_SEND: if(copy_from_user(&inout, (void *)arg, sizeof(inout))) return -EFAULT; buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL); if (buffer == NULL) return -ENOMEM; if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) { kfree(buffer); return -EFAULT; } vfc_lock_device(dev); inout.ret= vfc_i2c_sendbuf(dev,inout.addr & 0xff, inout.buffer,inout.len); if (copy_to_user((void *)arg,&inout,sizeof(inout))) { kfree(buffer); return -EFAULT; } vfc_unlock_device(dev); break; case VFC_I2C_RECV: if (copy_from_user(&inout, (void *)arg, sizeof(inout))) return -EFAULT; buffer = kmalloc(inout.len, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; memset(buffer,0,inout.len*sizeof(char)); vfc_lock_device(dev); inout.ret= vfc_i2c_recvbuf(dev,inout.addr & 0xff ,buffer,inout.len); vfc_unlock_device(dev); if (copy_to_user(inout.buffer, buffer, inout.len)) { kfree(buffer); return -EFAULT; } if (copy_to_user((void *)arg,&inout,sizeof(inout))) { kfree(buffer); return -EFAULT; } kfree(buffer); break; default: return -EINVAL; }; return 0;}int vfc_capture_start(struct vfc_dev *dev) { vfc_captstat_reset(dev); dev->control_reg = sbus_readl(&dev->regs->control); if((dev->control_reg & VFC_STATUS_CAPTURE)) { printk(KERN_ERR "vfc%d: vfc capture status not reset\n", dev->instance); return -EIO; } vfc_lock_device(dev); dev->control_reg &= ~VFC_CONTROL_CAPTURE; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg |= VFC_CONTROL_CAPTURE; sbus_writel(dev->control_reg, &dev->regs->control); dev->control_reg &= ~VFC_CONTROL_CAPTURE; sbus_writel(dev->control_reg, &dev->regs->control); vfc_unlock_device(dev); return 0;}int vfc_capture_poll(struct vfc_dev *dev) { int timeout = 1000; while (!timeout--) { if (dev->regs->control & VFC_STATUS_CAPTURE) break; vfc_i2c_delay_no_busy(dev, 100); } if(!timeout) { printk(KERN_WARNING "vfc%d: capture timed out\n", dev->instance); return -ETIMEDOUT; } return 0;}static int vfc_set_control_ioctl(struct inode *inode, struct file *file, struct vfc_dev *dev, unsigned long arg) { int setcmd, ret = 0; if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int))) return -EFAULT; VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", dev->instance,setcmd)); switch(setcmd) { case MEMPRST: vfc_lock_device(dev); vfc_memptr_reset(dev); vfc_unlock_device(dev); ret=0; break; case CAPTRCMD: vfc_capture_start(dev); vfc_capture_poll(dev); break; case DIAGMODE: if(capable(CAP_SYS_ADMIN)) { vfc_lock_device(dev); dev->control_reg |= VFC_CONTROL_DIAGMODE; sbus_writel(dev->control_reg, &dev->regs->control); vfc_unlock_device(dev); ret = 0; } else { ret = -EPERM; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -