📄 meye.c
字号:
break; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; int index = buf->index; if (index < 0 || index >= gbuffers) return -EINVAL; memset(buf, 0, sizeof(*buf)); buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->index = index; buf->bytesused = meye.grab_buffer[index].size; buf->flags = V4L2_BUF_FLAG_MAPPED; if (meye.grab_buffer[index].state == MEYE_BUF_USING) buf->flags |= V4L2_BUF_FLAG_QUEUED; if (meye.grab_buffer[index].state == MEYE_BUF_DONE) buf->flags |= V4L2_BUF_FLAG_DONE; buf->field = V4L2_FIELD_NONE; buf->timestamp = meye.grab_buffer[index].timestamp; buf->sequence = meye.grab_buffer[index].sequence; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = index * gbufsize; buf->length = gbufsize; break; } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (buf->index < 0 || buf->index >= gbuffers) return -EINVAL; if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) return -EINVAL; down(&meye.lock); buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags &= ~V4L2_BUF_FLAG_DONE; meye.grab_buffer[buf->index].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); up(&meye.lock); break; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; int reqnr; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; down(&meye.lock); if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { up(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, kfifo_len(meye.doneq) != 0) < 0) { up(&meye.lock); return -EINTR; } if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, sizeof(int))) { up(&meye.lock); return -EBUSY; } if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { up(&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; up(&meye.lock); break; } case VIDIOC_STREAMON: { down(&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: up(&meye.lock); return -EINVAL; } up(&meye.lock); break; } case VIDIOC_STREAMOFF: { int i; down(&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; up(&meye.lock); break; } /* * XXX what about private snapshot ioctls ? * Do they need to be converted to V4L2 ? */ default: return -ENOIOCTLCMD; } return 0;}static int meye_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, meye_do_ioctl);}static unsigned int meye_poll(struct file *file, poll_table *wait){ unsigned int res = 0; down(&meye.lock); poll_wait(file, &meye.proc_list, wait); if (kfifo_len(meye.doneq)) res = POLLIN | POLLRDNORM; up(&meye.lock); return res;}static void meye_vm_open(struct vm_area_struct *vma){ int idx = (int)vma->vm_private_data; meye.vma_use_count[idx]++;}static void meye_vm_close(struct vm_area_struct *vma){ int idx = (int)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; down(&meye.lock); if (size > gbuffers * gbufsize) { up(&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"); up(&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)) { up(&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); up(&meye.lock); return 0;}static struct file_operations meye_fops = { .owner = THIS_MODULE, .open = meye_open, .release = meye_release, .mmap = meye_mmap, .ioctl = meye_ioctl, .poll = meye_poll, .llseek = no_llseek,};static struct video_device meye_template = { .owner = THIS_MODULE, .name = "meye", .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_MEYE, .fops = &meye_fops, .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; u8 revision; if (meye.mchip_dev != NULL) { printk(KERN_ERR "meye: only one device allowed!\n"); goto outnotdev; } 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; } ret = -ENOMEM; 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->dev = &meye.mchip_dev->dev; if ((ret = sonypi_camera_command(SONYPI_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; } ret = -EIO; 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, SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq)) { printk(KERN_ERR "meye: request_irq failed\n"); goto outreqirq; } pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision); 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; } init_MUTEX(&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; sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32); sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32); sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32); sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48); printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n", MEYE_DRIVER_VERSION); printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n", revision, mchip_adr, meye.mchip_irq); 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: sonypi_camera_command(SONYPI_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); sonypi_camera_command(SONYPI_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -