📄 meye.c
字号:
remove_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_RUNNING; return -EINTR; } } remove_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_RUNNING; /* fall through */ case MEYE_BUF_DONE: meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; } break; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; int restart = 0; if (vm->frame >= gbuffers || vm->frame < 0) return -EINVAL; if (vm->format != VIDEO_PALETTE_YUV422) return -EINVAL; if (vm->height * vm->width * 2 > gbufsize) return -EINVAL; if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); if (vm->width == 640 && vm->height == 480) { if (meye.params.subsample) { meye.params.subsample = 0; restart = 1; } } else if (vm->width == 320 && vm->height == 240) { if (!meye.params.subsample) { meye.params.subsample = 1; restart = 1; } } else { up(&meye.lock); return -EINVAL; } if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT) mchip_continuous_start(); meye.grab_buffer[vm->frame].state = MEYE_BUF_USING; meye_pushq(&meye.grabq, vm->frame); up(&meye.lock); break; } case VIDIOCGMBUF: { struct video_mbuf *vm = arg; int i; memset(vm, 0 , sizeof(*vm)); vm->size = gbufsize * gbuffers; vm->frames = gbuffers; for (i = 0; i < gbuffers; i++) vm->offsets[i] = i * gbufsize; break; } case MEYEIOC_G_PARAMS: { struct meye_params *p = arg; *p = meye.params; break; } case MEYEIOC_S_PARAMS: { struct meye_params *jp = arg; if (jp->subsample > 1) return -EINVAL; if (jp->quality > 10) return -EINVAL; if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) return -EINVAL; if (jp->framerate > 31) return -EINVAL; down(&meye.lock); if (meye.params.subsample != jp->subsample || meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ meye.params = *jp; sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, meye.params.sharpness); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, meye.params.agc); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, meye.params.picture); up(&meye.lock); break; } case MEYEIOC_QBUF_CAPT: { int *nb = arg; if (!meye.grab_fbuffer) return -EINVAL; if (*nb >= gbuffers) return -EINVAL; if (*nb < 0) { /* stop capture */ mchip_hic_stop(); return 0; } if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) mchip_cont_compression_start(); meye.grab_buffer[*nb].state = MEYE_BUF_USING; meye_pushq(&meye.grabq, *nb); up(&meye.lock); break; } case MEYEIOC_SYNC: { int *i = arg; DECLARE_WAITQUEUE(wait, current); if (*i < 0 || *i >= gbuffers) return -EINVAL; switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: return -EINVAL; case MEYE_BUF_USING: add_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_INTERRUPTIBLE; while (meye.grab_buffer[*i].state == MEYE_BUF_USING) { schedule(); if(signal_pending(current)) { remove_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_RUNNING; return -EINTR; } } remove_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_RUNNING; /* fall through */ case MEYE_BUF_DONE: meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; } *i = meye.grab_buffer[*i].size; break; } case MEYEIOC_STILLCAPT: { if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; mchip_take_picture(); mchip_get_picture( meye.grab_fbuffer, mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[0].state = MEYE_BUF_DONE; up(&meye.lock); break; } case MEYEIOC_STILLJCAPT: { int *len = arg; if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; *len = -1; while (*len == -1) { mchip_take_picture(); *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); } meye.grab_buffer[0].state = MEYE_BUF_DONE; up(&meye.lock); break; } default: return -ENOIOCTLCMD; } /* switch */ 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 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 page, pos; down(&meye.lock); if (size > gbuffers * gbufsize) { up(&meye.lock); return -EINVAL; } if (!meye.grab_fbuffer) { /* 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; } } pos = (unsigned long)meye.grab_fbuffer; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { up(&meye.lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; size -= PAGE_SIZE; } 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, 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,};static int __devinit meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { int ret; unsigned long mchip_adr; u8 revision; if (meye.mchip_dev != NULL) { printk(KERN_ERR "meye: only one device allowed!\n"); ret = -EBUSY; goto out1; } sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1); meye.mchip_dev = pcidev; memcpy(&meye.video_dev, &meye_template, sizeof(meye_template)); if (mchip_dma_alloc()) { printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); ret = -ENOMEM; goto out2; } if ((ret = pci_enable_device(meye.mchip_dev))) { printk(KERN_ERR "meye: pci_enable_device failed\n"); goto out3; } meye.mchip_irq = pcidev->irq; mchip_adr = pci_resource_start(meye.mchip_dev,0); if (!mchip_adr) { printk(KERN_ERR "meye: mchip has no device base address\n"); ret = -EIO; goto out4; } if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), pci_resource_len(meye.mchip_dev, 0), "meye")) { ret = -EIO; printk(KERN_ERR "meye: request_mem_region failed\n"); goto out4; } pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision); pci_set_master(meye.mchip_dev); pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); if ((ret = request_irq(meye.mchip_irq, meye_irq, SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq))) { printk(KERN_ERR "meye: request_irq failed (ret=%d)\n", ret); goto out5; } meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); if (!meye.mchip_mmregs) { printk(KERN_ERR "meye: ioremap failed\n"); ret = -EIO; goto out6; } /* 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); wait_ms(1); mchip_set(MCHIP_VRJ_SOFT_RESET, 1); wait_ms(1); mchip_set(MCHIP_MM_PCI_MODE, 5); wait_ms(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"); ret = -EIO; goto out7; } printk(KERN_INFO "meye: Motion Eye Camera Driver v%d.%d.\n", MEYE_DRIVER_MAJORVERSION, MEYE_DRIVER_MINORVERSION); printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n", revision, mchip_adr, meye.mchip_irq); /* init all fields */ init_MUTEX(&meye.lock); meye.picture.depth = 2; 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 = 7; 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); return 0;out7: iounmap(meye.mchip_mmregs);out6: free_irq(meye.mchip_irq, meye_irq);out5: release_mem_region(pci_resource_start(meye.mchip_dev, 0), pci_resource_len(meye.mchip_dev, 0));out4: pci_disable_device(meye.mchip_dev);out3: mchip_dma_free();out2: sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);out1: return ret;}static void __devexit meye_remove(struct pci_dev *pcidev) { video_unregister_device(&meye.video_dev); mchip_hic_stop(); /* 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); mchip_dma_free(); if (meye.grab_fbuffer) rvfree(meye.grab_fbuffer, gbuffers*gbufsize); sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0); printk(KERN_INFO "meye: removed\n");}static struct pci_device_id meye_pci_tbl[] __devinitdata = { { 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),};static int __init meye_init_module(void) { if (gbuffers < 2) gbuffers = 2; if (gbuffers > MEYE_MAX_BUFNBRS) gbuffers = MEYE_MAX_BUFNBRS; if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n", gbuffers, gbufsize/1024, gbuffers*gbufsize/1024); return pci_module_init(&meye_driver);}static void __exit meye_cleanup_module(void) { pci_unregister_driver(&meye_driver);}#ifndef MODULEstatic int __init meye_setup(char *str) { int ints[4]; str = get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] <= 0) goto out; gbuffers = ints[1]; if (ints[0] == 1) goto out; gbufsize = ints[2]; if (ints[0] == 2) goto out; video_nr = ints[3];out: return 1;}__setup("meye=", meye_setup);#endifMODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");MODULE_DESCRIPTION("video4linux driver for the MotionEye camera");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;MODULE_PARM(gbuffers,"i");MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (32 max)");MODULE_PARM(gbufsize,"i");MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 614400");MODULE_PARM(video_nr,"i");MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");/* Module entry points */module_init(meye_init_module);module_exit(meye_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -