⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cafe_ccic.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
static void cafe_v4l_dev_release(struct video_device *vd){	struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);	kfree(cam);}/* * This template device holds all of those v4l2 methods; we * clone it for specific real devices. */static const struct file_operations cafe_v4l_fops = {	.owner = THIS_MODULE,	.open = cafe_v4l_open,	.release = cafe_v4l_release,	.read = cafe_v4l_read,	.poll = cafe_v4l_poll,	.mmap = cafe_v4l_mmap,	.ioctl = video_ioctl2,	.llseek = no_llseek,};static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {	.vidioc_querycap 	= cafe_vidioc_querycap,	.vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,	.vidioc_try_fmt_vid_cap	= cafe_vidioc_try_fmt_vid_cap,	.vidioc_s_fmt_vid_cap	= cafe_vidioc_s_fmt_vid_cap,	.vidioc_g_fmt_vid_cap	= cafe_vidioc_g_fmt_vid_cap,	.vidioc_enum_input	= cafe_vidioc_enum_input,	.vidioc_g_input		= cafe_vidioc_g_input,	.vidioc_s_input		= cafe_vidioc_s_input,	.vidioc_s_std		= cafe_vidioc_s_std,	.vidioc_reqbufs		= cafe_vidioc_reqbufs,	.vidioc_querybuf	= cafe_vidioc_querybuf,	.vidioc_qbuf		= cafe_vidioc_qbuf,	.vidioc_dqbuf		= cafe_vidioc_dqbuf,	.vidioc_streamon	= cafe_vidioc_streamon,	.vidioc_streamoff	= cafe_vidioc_streamoff,	.vidioc_queryctrl	= cafe_vidioc_queryctrl,	.vidioc_g_ctrl		= cafe_vidioc_g_ctrl,	.vidioc_s_ctrl		= cafe_vidioc_s_ctrl,	.vidioc_g_parm		= cafe_vidioc_g_parm,	.vidioc_s_parm		= cafe_vidioc_s_parm,};static struct video_device cafe_v4l_template = {	.name = "cafe",	.minor = -1, /* Get one dynamically */	.tvnorms = V4L2_STD_NTSC_M,	.current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */	.fops = &cafe_v4l_fops,	.ioctl_ops = &cafe_v4l_ioctl_ops,	.release = cafe_v4l_dev_release,};/* ---------------------------------------------------------------------- *//* * Interrupt handler stuff */static void cafe_frame_tasklet(unsigned long data){	struct cafe_camera *cam = (struct cafe_camera *) data;	int i;	unsigned long flags;	struct cafe_sio_buffer *sbuf;	spin_lock_irqsave(&cam->dev_lock, flags);	for (i = 0; i < cam->nbufs; i++) {		int bufno = cam->next_buf;		if (bufno < 0) {  /* "will never happen" */			cam_err(cam, "No valid bufs in tasklet!\n");			break;		}		if (++(cam->next_buf) >= cam->nbufs)			cam->next_buf = 0;		if (! test_bit(bufno, &cam->flags))			continue;		if (list_empty(&cam->sb_avail))			break;  /* Leave it valid, hope for better later */		clear_bit(bufno, &cam->flags);		sbuf = list_entry(cam->sb_avail.next,				struct cafe_sio_buffer, list);		/*		 * Drop the lock during the big copy.  This *should* be safe...		 */		spin_unlock_irqrestore(&cam->dev_lock, flags);		memcpy(sbuf->buffer, cam->dma_bufs[bufno],				cam->pix_format.sizeimage);		sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;		sbuf->v4lbuf.sequence = cam->buf_seq[bufno];		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;		sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;		spin_lock_irqsave(&cam->dev_lock, flags);		list_move_tail(&sbuf->list, &cam->sb_full);	}	if (! list_empty(&cam->sb_full))		wake_up(&cam->iowait);	spin_unlock_irqrestore(&cam->dev_lock, flags);}static void cafe_frame_complete(struct cafe_camera *cam, int frame){	/*	 * Basic frame housekeeping.	 */	if (test_bit(frame, &cam->flags) && printk_ratelimit())		cam_err(cam, "Frame overrun on %d, frames lost\n", frame);	set_bit(frame, &cam->flags);	clear_bit(CF_DMA_ACTIVE, &cam->flags);	if (cam->next_buf < 0)		cam->next_buf = frame;	cam->buf_seq[frame] = ++(cam->sequence);	switch (cam->state) {	/*	 * If in single read mode, try going speculative.	 */	    case S_SINGLEREAD:		cam->state = S_SPECREAD;		cam->specframes = 0;		wake_up(&cam->iowait);		break;	/*	 * If we are already doing speculative reads, and nobody is	 * reading them, just stop.	 */	    case S_SPECREAD:		if (++(cam->specframes) >= cam->nbufs) {			cafe_ctlr_stop(cam);			cafe_ctlr_irq_disable(cam);			cam->state = S_IDLE;		}		wake_up(&cam->iowait);		break;	/*	 * For the streaming case, we defer the real work to the	 * camera tasklet.	 *	 * FIXME: if the application is not consuming the buffers,	 * we should eventually put things on hold and restart in	 * vidioc_dqbuf().	 */	    case S_STREAMING:		tasklet_schedule(&cam->s_tasklet);		break;	    default:		cam_err(cam, "Frame interrupt in non-operational state\n");		break;	}}static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs){	unsigned int frame;	cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */	/*	 * Handle any frame completions.  There really should	 * not be more than one of these, or we have fallen	 * far behind.	 */	for (frame = 0; frame < cam->nbufs; frame++)		if (irqs & (IRQ_EOF0 << frame))			cafe_frame_complete(cam, frame);	/*	 * If a frame starts, note that we have DMA active.  This	 * code assumes that we won't get multiple frame interrupts	 * at once; may want to rethink that.	 */	if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))		set_bit(CF_DMA_ACTIVE, &cam->flags);}static irqreturn_t cafe_irq(int irq, void *data){	struct cafe_camera *cam = data;	unsigned int irqs;	spin_lock(&cam->dev_lock);	irqs = cafe_reg_read(cam, REG_IRQSTAT);	if ((irqs & ALLIRQS) == 0) {		spin_unlock(&cam->dev_lock);		return IRQ_NONE;	}	if (irqs & FRAMEIRQS)		cafe_frame_irq(cam, irqs);	if (irqs & TWSIIRQS) {		cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);		wake_up(&cam->smbus_wait);	}	spin_unlock(&cam->dev_lock);	return IRQ_HANDLED;}/* -------------------------------------------------------------------------- */#ifdef CONFIG_VIDEO_ADV_DEBUG/* * Debugfs stuff. */static char cafe_debug_buf[1024];static struct dentry *cafe_dfs_root;static void cafe_dfs_setup(void){	cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);	if (IS_ERR(cafe_dfs_root)) {		cafe_dfs_root = NULL;  /* Never mind */		printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");	}}static void cafe_dfs_shutdown(void){	if (cafe_dfs_root)		debugfs_remove(cafe_dfs_root);}static int cafe_dfs_open(struct inode *inode, struct file *file){	file->private_data = inode->i_private;	return 0;}static ssize_t cafe_dfs_read_regs(struct file *file,		char __user *buf, size_t count, loff_t *ppos){	struct cafe_camera *cam = file->private_data;	char *s = cafe_debug_buf;	int offset;	for (offset = 0; offset < 0x44; offset += 4)		s += sprintf(s, "%02x: %08x\n", offset,				cafe_reg_read(cam, offset));	for (offset = 0x88; offset <= 0x90; offset += 4)		s += sprintf(s, "%02x: %08x\n", offset,				cafe_reg_read(cam, offset));	for (offset = 0xb4; offset <= 0xbc; offset += 4)		s += sprintf(s, "%02x: %08x\n", offset,				cafe_reg_read(cam, offset));	for (offset = 0x3000; offset <= 0x300c; offset += 4)		s += sprintf(s, "%04x: %08x\n", offset,				cafe_reg_read(cam, offset));	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,			s - cafe_debug_buf);}static const struct file_operations cafe_dfs_reg_ops = {	.owner = THIS_MODULE,	.read = cafe_dfs_read_regs,	.open = cafe_dfs_open};static ssize_t cafe_dfs_read_cam(struct file *file,		char __user *buf, size_t count, loff_t *ppos){	struct cafe_camera *cam = file->private_data;	char *s = cafe_debug_buf;	int offset;	if (! cam->sensor)		return -EINVAL;	for (offset = 0x0; offset < 0x8a; offset++)	{		u8 v;		cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);		s += sprintf(s, "%02x: %02x\n", offset, v);	}	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,			s - cafe_debug_buf);}static const struct file_operations cafe_dfs_cam_ops = {	.owner = THIS_MODULE,	.read = cafe_dfs_read_cam,	.open = cafe_dfs_open};static void cafe_dfs_cam_setup(struct cafe_camera *cam){	char fname[40];	if (!cafe_dfs_root)		return;	sprintf(fname, "regs-%d", cam->v4ldev.num);	cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,			cam, &cafe_dfs_reg_ops);	sprintf(fname, "cam-%d", cam->v4ldev.num);	cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,			cam, &cafe_dfs_cam_ops);}static void cafe_dfs_cam_shutdown(struct cafe_camera *cam){	if (! IS_ERR(cam->dfs_regs))		debugfs_remove(cam->dfs_regs);	if (! IS_ERR(cam->dfs_cam_regs))		debugfs_remove(cam->dfs_cam_regs);}#else#define cafe_dfs_setup()#define cafe_dfs_shutdown()#define cafe_dfs_cam_setup(cam)#define cafe_dfs_cam_shutdown(cam)#endif    /* CONFIG_VIDEO_ADV_DEBUG *//* ------------------------------------------------------------------------*//* * PCI interface stuff. */static int cafe_pci_probe(struct pci_dev *pdev,		const struct pci_device_id *id){	int ret;	struct cafe_camera *cam;	/*	 * Start putting together one of our big camera structures.	 */	ret = -ENOMEM;	cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);	if (cam == NULL)		goto out;	mutex_init(&cam->s_mutex);	mutex_lock(&cam->s_mutex);	spin_lock_init(&cam->dev_lock);	cam->state = S_NOTREADY;	cafe_set_config_needed(cam, 1);	init_waitqueue_head(&cam->smbus_wait);	init_waitqueue_head(&cam->iowait);	cam->pdev = pdev;	cam->pix_format = cafe_def_pix_format;	INIT_LIST_HEAD(&cam->dev_list);	INIT_LIST_HEAD(&cam->sb_avail);	INIT_LIST_HEAD(&cam->sb_full);	tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);	/*	 * Get set up on the PCI bus.	 */	ret = pci_enable_device(pdev);	if (ret)		goto out_free;	pci_set_master(pdev);	ret = -EIO;	cam->regs = pci_iomap(pdev, 0, 0);	if (! cam->regs) {		printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");		goto out_free;	}	ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);	if (ret)		goto out_iounmap;	/*	 * Initialize the controller and leave it powered up.  It will	 * stay that way until the sensor driver shows up.	 */	cafe_ctlr_init(cam);	cafe_ctlr_power_up(cam);	/*	 * Set up I2C/SMBUS communications.  We have to drop the mutex here	 * because the sensor could attach in this call chain, leading to	 * unsightly deadlocks.	 */	mutex_unlock(&cam->s_mutex);  /* attach can deadlock */	ret = cafe_smbus_setup(cam);	if (ret)		goto out_freeirq;	/*	 * Get the v4l2 setup done.	 */	mutex_lock(&cam->s_mutex);	cam->v4ldev = cafe_v4l_template;	cam->v4ldev.debug = 0;//	cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;	cam->v4ldev.parent = &pdev->dev;	ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);	if (ret)		goto out_smbus;	/*	 * If so requested, try to get our DMA buffers now.	 */	if (!alloc_bufs_at_read) {		if (cafe_alloc_dma_bufs(cam, 1))			cam_warn(cam, "Unable to alloc DMA buffers at load"					" will try again later.");	}	cafe_dfs_cam_setup(cam);	mutex_unlock(&cam->s_mutex);	cafe_add_dev(cam);	return 0;  out_smbus:	cafe_smbus_shutdown(cam);  out_freeirq:	cafe_ctlr_power_down(cam);	free_irq(pdev->irq, cam);  out_iounmap:	pci_iounmap(pdev, cam->regs);  out_free:	kfree(cam);  out:	return ret;}/* * Shut down an initialized device */static void cafe_shutdown(struct cafe_camera *cam){/* FIXME: Make sure we take care of everything here */	cafe_dfs_cam_shutdown(cam);	if (cam->n_sbufs > 0)		/* What if they are still mapped?  Shouldn't be, but... */		cafe_free_sio_buffers(cam);	cafe_remove_dev(cam);	cafe_ctlr_stop_dma(cam);	cafe_ctlr_power_down(cam);	cafe_smbus_shutdown(cam);	cafe_free_dma_bufs(cam);	free_irq(cam->pdev->irq, cam);	pci_iounmap(cam->pdev, cam->regs);	video_unregister_device(&cam->v4ldev);	/* kfree(cam); done in v4l_release () */}static void cafe_pci_remove(struct pci_dev *pdev){	struct cafe_camera *cam = cafe_find_by_pdev(pdev);	if (cam == NULL) {		printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);		return;	}	mutex_lock(&cam->s_mutex);	if (cam->users > 0)		cam_warn(cam, "Removing a device with users!\n");	cafe_shutdown(cam);/* No unlock - it no longer exists */}#ifdef CONFIG_PM/* * Basic power management. */static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state){	struct cafe_camera *cam = cafe_find_by_pdev(pdev);	int ret;	enum cafe_state cstate;	ret = pci_save_state(pdev);	if (ret)		return ret;	cstate = cam->state; /* HACK - stop_dma sets to idle */	cafe_ctlr_stop_dma(cam);	cafe_ctlr_power_down(cam);	pci_disable_device(pdev);	cam->state = cstate;	return 0;}static int cafe_pci_resume(struct pci_dev *pdev){	struct cafe_camera *cam = cafe_find_by_pdev(pdev);	int ret = 0;	ret = pci_restore_state(pdev);	if (ret)		return ret;	ret = pci_enable_device(pdev);	if (ret) {		cam_warn(cam, "Unable to re-enable device on resume!\n");		return ret;	}	cafe_ctlr_init(cam);	cafe_ctlr_power_down(cam);	mutex_lock(&cam->s_mutex);	if (cam->users > 0) {		cafe_ctlr_power_up(cam);		__cafe_cam_reset(cam);	}	mutex_unlock(&cam->s_mutex);	set_bit(CF_CONFIG_NEEDED, &cam->flags);	if (cam->state == S_SPECREAD)		cam->state = S_IDLE;  /* Don't bother restarting */	else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)		ret = cafe_read_setup(cam, cam->state);	return ret;}#endif  /* CONFIG_PM */static struct pci_device_id cafe_ids[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL,		     PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },	{ 0, }};MODULE_DEVICE_TABLE(pci, cafe_ids);static struct pci_driver cafe_pci_driver = {	.name = "cafe1000-ccic",	.id_table = cafe_ids,	.probe = cafe_pci_probe,	.remove = cafe_pci_remove,#ifdef CONFIG_PM	.suspend = cafe_pci_suspend,	.resume = cafe_pci_resume,#endif};static int __init cafe_init(void){	int ret;	printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",			CAFE_VERSION);	cafe_dfs_setup();	ret = pci_register_driver(&cafe_pci_driver);	if (ret) {		printk(KERN_ERR "Unable to register cafe_ccic driver\n");		goto out;	}	request_module("ov7670");  /* FIXME want something more general */	ret = 0;  out:	return ret;}static void __exit cafe_exit(void){	pci_unregister_driver(&cafe_pci_driver);	cafe_dfs_shutdown();}module_init(cafe_init);module_exit(cafe_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -