meye.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,009 行 · 第 1/4 页

C
2,009
字号
	mutex_lock(&meye.lock);	if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {		mutex_unlock(&meye.lock);		return -EAGAIN;	}	if (wait_event_interruptible(meye.proc_list,				     kfifo_len(meye.doneq) != 0) < 0) {		mutex_unlock(&meye.lock);		return -EINTR;	}	if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,		       sizeof(int))) {		mutex_unlock(&meye.lock);		return -EBUSY;	}	if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {		mutex_unlock(&meye.lock);		return -EINVAL;	}	buf->index = reqnr;	buf->bytesused = meye.grab_buffer[reqnr].size;	buf->flags = V4L2_BUF_FLAG_MAPPED;	buf->field = V4L2_FIELD_NONE;	buf->timestamp = meye.grab_buffer[reqnr].timestamp;	buf->sequence = meye.grab_buffer[reqnr].sequence;	buf->memory = V4L2_MEMORY_MMAP;	buf->m.offset = reqnr * gbufsize;	buf->length = gbufsize;	meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;	mutex_unlock(&meye.lock);	return 0;}static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i){	mutex_lock(&meye.lock);	switch (meye.mchip_mode) {	case MCHIP_HIC_MODE_CONT_OUT:		mchip_continuous_start();		break;	case MCHIP_HIC_MODE_CONT_COMP:		mchip_cont_compression_start();		break;	default:		mutex_unlock(&meye.lock);		return -EINVAL;	}	mutex_unlock(&meye.lock);	return 0;}static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i){	mutex_lock(&meye.lock);	mchip_hic_stop();	kfifo_reset(meye.grabq);	kfifo_reset(meye.doneq);	for (i = 0; i < MEYE_MAX_BUFNBRS; i++)		meye.grab_buffer[i].state = MEYE_BUF_UNUSED;	mutex_unlock(&meye.lock);	return 0;}static int vidioc_default(struct file *file, void *fh, int cmd, void *arg){	switch (cmd) {	case MEYEIOC_G_PARAMS:		return meyeioc_g_params((struct meye_params *) arg);	case MEYEIOC_S_PARAMS:		return meyeioc_s_params((struct meye_params *) arg);	case MEYEIOC_QBUF_CAPT:		return meyeioc_qbuf_capt((int *) arg);	case MEYEIOC_SYNC:		return meyeioc_sync(file, fh, (int *) arg);	case MEYEIOC_STILLCAPT:		return meyeioc_stillcapt();	case MEYEIOC_STILLJCAPT:		return meyeioc_stilljcapt((int *) arg);	default:		return -EINVAL;	}}static unsigned int meye_poll(struct file *file, poll_table *wait){	unsigned int res = 0;	mutex_lock(&meye.lock);	poll_wait(file, &meye.proc_list, wait);	if (kfifo_len(meye.doneq))		res = POLLIN | POLLRDNORM;	mutex_unlock(&meye.lock);	return res;}static void meye_vm_open(struct vm_area_struct *vma){	long idx = (long)vma->vm_private_data;	meye.vma_use_count[idx]++;}static void meye_vm_close(struct vm_area_struct *vma){	long idx = (long)vma->vm_private_data;	meye.vma_use_count[idx]--;}static struct vm_operations_struct meye_vm_ops = {	.open		= meye_vm_open,	.close		= meye_vm_close,};static int meye_mmap(struct file *file, struct vm_area_struct *vma){	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, pos;	mutex_lock(&meye.lock);	if (size > gbuffers * gbufsize) {		mutex_unlock(&meye.lock);		return -EINVAL;	}	if (!meye.grab_fbuffer) {		int i;		/* lazy allocation */		meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);		if (!meye.grab_fbuffer) {			printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");			mutex_unlock(&meye.lock);			return -ENOMEM;		}		for (i = 0; i < gbuffers; i++)			meye.vma_use_count[i] = 0;	}	pos = (unsigned long)meye.grab_fbuffer + offset;	while (size > 0) {		page = vmalloc_to_pfn((void *)pos);		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {			mutex_unlock(&meye.lock);			return -EAGAIN;		}		start += PAGE_SIZE;		pos += PAGE_SIZE;		if (size > PAGE_SIZE)			size -= PAGE_SIZE;		else			size = 0;	}	vma->vm_ops = &meye_vm_ops;	vma->vm_flags &= ~VM_IO;	/* not I/O memory */	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */	vma->vm_private_data = (void *) (offset / gbufsize);	meye_vm_open(vma);	mutex_unlock(&meye.lock);	return 0;}static const struct file_operations meye_fops = {	.owner		= THIS_MODULE,	.open		= meye_open,	.release	= meye_release,	.mmap		= meye_mmap,	.ioctl		= video_ioctl2,#ifdef CONFIG_COMPAT	.compat_ioctl	= v4l_compat_ioctl32,#endif	.poll		= meye_poll,	.llseek		= no_llseek,};static const struct v4l2_ioctl_ops meye_ioctl_ops = {	.vidioc_querycap	= vidioc_querycap,	.vidioc_enum_input	= vidioc_enum_input,	.vidioc_g_input		= vidioc_g_input,	.vidioc_s_input		= vidioc_s_input,	.vidioc_queryctrl	= vidioc_queryctrl,	.vidioc_s_ctrl		= vidioc_s_ctrl,	.vidioc_g_ctrl		= vidioc_g_ctrl,	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,	.vidioc_reqbufs		= vidioc_reqbufs,	.vidioc_querybuf	= vidioc_querybuf,	.vidioc_qbuf		= vidioc_qbuf,	.vidioc_dqbuf		= vidioc_dqbuf,	.vidioc_streamon	= vidioc_streamon,	.vidioc_streamoff	= vidioc_streamoff,	.vidioc_default		= vidioc_default,};static struct video_device meye_template = {	.name		= "meye",	.fops		= &meye_fops,	.ioctl_ops 	= &meye_ioctl_ops,	.release	= video_device_release,	.minor		= -1,};#ifdef CONFIG_PMstatic int meye_suspend(struct pci_dev *pdev, pm_message_t state){	pci_save_state(pdev);	meye.pm_mchip_mode = meye.mchip_mode;	mchip_hic_stop();	mchip_set(MCHIP_MM_INTA, 0x0);	return 0;}static int meye_resume(struct pci_dev *pdev){	pci_restore_state(pdev);	pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);	mchip_delay(MCHIP_HIC_CMD, 0);	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);	msleep(1);	mchip_set(MCHIP_VRJ_SOFT_RESET, 1);	msleep(1);	mchip_set(MCHIP_MM_PCI_MODE, 5);	msleep(1);	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);	switch (meye.pm_mchip_mode) {	case MCHIP_HIC_MODE_CONT_OUT:		mchip_continuous_start();		break;	case MCHIP_HIC_MODE_CONT_COMP:		mchip_cont_compression_start();		break;	}	return 0;}#endifstatic int __devinit meye_probe(struct pci_dev *pcidev,				const struct pci_device_id *ent){	int ret = -EBUSY;	unsigned long mchip_adr;	if (meye.mchip_dev != NULL) {		printk(KERN_ERR "meye: only one device allowed!\n");		goto outnotdev;	}	ret = -ENOMEM;	meye.mchip_dev = pcidev;	meye.video_dev = video_device_alloc();	if (!meye.video_dev) {		printk(KERN_ERR "meye: video_device_alloc() failed!\n");		goto outnotdev;	}	meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);	if (!meye.grab_temp) {		printk(KERN_ERR "meye: grab buffer allocation failed\n");		goto outvmalloc;	}	spin_lock_init(&meye.grabq_lock);	meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,				 &meye.grabq_lock);	if (IS_ERR(meye.grabq)) {		printk(KERN_ERR "meye: fifo allocation failed\n");		goto outkfifoalloc1;	}	spin_lock_init(&meye.doneq_lock);	meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,				 &meye.doneq_lock);	if (IS_ERR(meye.doneq)) {		printk(KERN_ERR "meye: fifo allocation failed\n");		goto outkfifoalloc2;	}	memcpy(meye.video_dev, &meye_template, sizeof(meye_template));	meye.video_dev->parent = &meye.mchip_dev->dev;	ret = -EIO;	if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {		printk(KERN_ERR "meye: unable to power on the camera\n");		printk(KERN_ERR "meye: did you enable the camera in "				"sonypi using the module options ?\n");		goto outsonypienable;	}	if ((ret = pci_enable_device(meye.mchip_dev))) {		printk(KERN_ERR "meye: pci_enable_device failed\n");		goto outenabledev;	}	mchip_adr = pci_resource_start(meye.mchip_dev,0);	if (!mchip_adr) {		printk(KERN_ERR "meye: mchip has no device base address\n");		goto outregions;	}	if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),				pci_resource_len(meye.mchip_dev, 0),				"meye")) {		printk(KERN_ERR "meye: request_mem_region failed\n");		goto outregions;	}	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);	if (!meye.mchip_mmregs) {		printk(KERN_ERR "meye: ioremap failed\n");		goto outremap;	}	meye.mchip_irq = pcidev->irq;	if (request_irq(meye.mchip_irq, meye_irq,			IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) {		printk(KERN_ERR "meye: request_irq failed\n");		goto outreqirq;	}	pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8);	pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64);	pci_set_master(meye.mchip_dev);	/* Ask the camera to perform a soft reset. */	pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);	mchip_delay(MCHIP_HIC_CMD, 0);	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);	msleep(1);	mchip_set(MCHIP_VRJ_SOFT_RESET, 1);	msleep(1);	mchip_set(MCHIP_MM_PCI_MODE, 5);	msleep(1);	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);	if (video_register_device(meye.video_dev, VFL_TYPE_GRABBER,				  video_nr) < 0) {		printk(KERN_ERR "meye: video_register_device failed\n");		goto outvideoreg;	}	mutex_init(&meye.lock);	init_waitqueue_head(&meye.proc_list);	meye.picture.depth = 16;	meye.picture.palette = VIDEO_PALETTE_YUV422;	meye.picture.brightness = 32 << 10;	meye.picture.hue = 32 << 10;	meye.picture.colour = 32 << 10;	meye.picture.contrast = 32 << 10;	meye.picture.whiteness = 0;	meye.params.subsample = 0;	meye.params.quality = 8;	meye.params.sharpness = 32;	meye.params.agc = 48;	meye.params.picture = 0;	meye.params.framerate = 0;	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);	printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",	       MEYE_DRIVER_VERSION);#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)	printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n",	       meye.mchip_dev->revision, mchip_adr, meye.mchip_irq);#else	printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n",	       v4l_compat_pci_rev(meye.mchip_dev), mchip_adr, meye.mchip_irq);#endif	return 0;outvideoreg:	free_irq(meye.mchip_irq, meye_irq);outreqirq:	iounmap(meye.mchip_mmregs);outremap:	release_mem_region(pci_resource_start(meye.mchip_dev, 0),			   pci_resource_len(meye.mchip_dev, 0));outregions:	pci_disable_device(meye.mchip_dev);outenabledev:	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);outsonypienable:	kfifo_free(meye.doneq);outkfifoalloc2:	kfifo_free(meye.grabq);outkfifoalloc1:	vfree(meye.grab_temp);outvmalloc:	video_device_release(meye.video_dev);outnotdev:	return ret;}static void __devexit meye_remove(struct pci_dev *pcidev){	video_unregister_device(meye.video_dev);	mchip_hic_stop();	mchip_dma_free();	/* disable interrupts */	mchip_set(MCHIP_MM_INTA, 0x0);	free_irq(meye.mchip_irq, meye_irq);	iounmap(meye.mchip_mmregs);	release_mem_region(pci_resource_start(meye.mchip_dev, 0),			   pci_resource_len(meye.mchip_dev, 0));	pci_disable_device(meye.mchip_dev);	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);	kfifo_free(meye.doneq);	kfifo_free(meye.grabq);	vfree(meye.grab_temp);	if (meye.grab_fbuffer) {		rvfree(meye.grab_fbuffer, gbuffers*gbufsize);		meye.grab_fbuffer = NULL;	}	printk(KERN_INFO "meye: removed\n");}static struct pci_device_id meye_pci_tbl[] = {	{ PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ }};MODULE_DEVICE_TABLE(pci, meye_pci_tbl);static struct pci_driver meye_driver = {	.name		= "meye",	.id_table	= meye_pci_tbl,	.probe		= meye_probe,	.remove		= __devexit_p(meye_remove),#ifdef CONFIG_PM	.suspend	= meye_suspend,	.resume		= meye_resume,#endif};static int __init meye_init(void){	gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS));	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)		gbufsize = MEYE_MAX_BUFSIZE;	gbufsize = PAGE_ALIGN(gbufsize);	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "			 "for capture\n",			 gbuffers,			 gbufsize / 1024, gbuffers * gbufsize / 1024);	return pci_register_driver(&meye_driver);}static void __exit meye_exit(void){	pci_unregister_driver(&meye_driver);}module_init(meye_init);module_exit(meye_exit);

⌨️ 快捷键说明

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