📄 videodevx.c
字号:
len = 0; len += sprintf(buf, "Video for Linux Two (V%d.%d alpha)." " Major device: %d\n", V4L2_MAJOR_VERSION, V4L2_MINOR_VERSION, v4l2_major); //len += sprintf(buf+len,"minor: type busy name\n"); for (i = 0; i < V4L2_NUM_DEVICES; i++) { vfl = v4l2_device[i]; if (vfl == NULL) continue; if (len > (PAGE_SIZE - 80)) return len; if (vfl->type >= 0 && vfl->type < sizeof(device_types)/sizeof(char*)) t = device_types[vfl->type]; else if (vfl->type >= V4L2_TYPE_PRIVATE) t = "private"; else t = "undef"; len += sprintf(buf+len, "%5d: %-9s %3d %s\n", vfl->minor, t, vfl->busy, vfl->name); } len += sprintf(buf+len, "Video for Linux One\n"); for (i = 0; i < VIDEO_NUM_DEVICES; i++) { vfl1 = video_device[i]; if (vfl1 == NULL) continue; if (len > (PAGE_SIZE - 80)) return len; len += sprintf(buf+len, "%5d: v4l1 capture device %3d %s\n", vfl1->minor, vfl1->busy, vfl1->name); } return len;}#endif#if LINUX_VERSION_CODE < 0x020300/* Original /proc file code from Erik Walthinsen */static intvideo_read_proc(char *buf, char **start, off_t offset, int len, int unused){ return video_build_proc(buf, start, offset, len, NULL);}/* proc file for /proc/videodev */static struct proc_dir_entry video_proc_entry ={ 0, 8, "videodev", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, &video_read_proc};#else /* 2.3 */#if defined(CONFIG_PROC_FS)struct videodev_proc_data { struct list_head proc_list; char name[16]; struct video_device *vdev; struct v4l2_device *v2dev; struct proc_dir_entry *proc_entry;};static struct proc_dir_entry *video_dev_proc_entry = NULL;struct proc_dir_entry *video_proc_entry = NULL;EXPORT_SYMBOL(video_proc_entry);LIST_HEAD(videodev_proc_list);static int videodev_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0; struct videodev_proc_data *d = 0; struct list_head *tmp; list_for_each (tmp, &videodev_proc_list) { d = list_entry(tmp, struct videodev_proc_data, proc_list); if ((data == d->vdev) || (data == d->v2dev)) break; } /* not found */ if (tmp == &videodev_proc_list) return 0;#if 1/* Check whether we are opening a V4L1 or V4L2 device */ if (d->vdev) len = sprintf(page, "Video4Linux1 device:\n" " Name:\td->vdev->name\n" " Minor:\td->vdev->minor\n"); else if (d->v2dev) len = sprintf(page, "Video4Linux2 device:\n" " Name: \t%s\n" " Minor:\t%d\n" " Type: \t%s\n", d->v2dev->name, d->v2dev->minor, (d->v2dev->type > V4L2_TYPE_PRIVATE) ? "undef" : device_types[d->v2dev->type]); else panic("vdev proc: none of V4L1 or V4L2");#else len = video_build_proc(page, start, off, count, data);#endif /* fix the read count. Not so important, since usually we only do cat /proc.. */ len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; } else len = count; *start = page + off; return len;}static void videodev_proc_create(void){ video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root); if (video_proc_entry == NULL) { printk("video_dev: unable to initialise /proc/video\n"); return; } video_proc_entry->owner = THIS_MODULE; video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry); if (video_dev_proc_entry == NULL) { printk("video_dev: unable to initialise /proc/video/dev\n"); return; } video_dev_proc_entry->owner = THIS_MODULE;}#ifdef MODULE#if defined(CONFIG_PROC_FS)static void videodev_proc_destroy(void){ if (video_dev_proc_entry != NULL) remove_proc_entry("dev", video_proc_entry); if (video_proc_entry != NULL) remove_proc_entry("video", &proc_root);}#endif#endifstatic void videodev_proc_create_dev (struct video_device *vfd, char *name){ struct videodev_proc_data *d; struct proc_dir_entry *p; if (video_dev_proc_entry == NULL) return; d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL); if (!d) return; p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry); p->data = vfd; p->read_proc = videodev_proc_read; d->proc_entry = p; d->vdev = vfd; d->v2dev = NULL; /* not a V4L2 device */ strcpy (d->name, name); list_add (&d->proc_list, &videodev_proc_list);}static void videodev_proc_destroy_dev (struct video_device *vfd){ struct list_head *tmp; struct videodev_proc_data *d; list_for_each (tmp, &videodev_proc_list) { d = list_entry(tmp, struct videodev_proc_data, proc_list); if (vfd == d->vdev) { remove_proc_entry(d->name, video_dev_proc_entry); list_del (&d->proc_list); kfree (d); break; } }}static void v4l2_proc_create_dev (struct v4l2_device *vfd, char *name){ struct videodev_proc_data *d; struct proc_dir_entry *p; if (video_dev_proc_entry == NULL) return; d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL); if (!d) return; p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry); p->data = vfd; p->read_proc = videodev_proc_read; d->proc_entry = p; d->vdev = NULL; /* not a V4L device */ d->v2dev = vfd; strcpy (d->name, name); list_add (&d->proc_list, &videodev_proc_list);}static void v4l2_proc_destroy_dev (struct v4l2_device *vfd){ struct list_head *tmp; struct videodev_proc_data *d; list_for_each (tmp, &videodev_proc_list) { d = list_entry(tmp, struct videodev_proc_data, proc_list); if (vfd == d->v2dev) { remove_proc_entry(d->name, video_dev_proc_entry); list_del (&d->proc_list); kfree (d); break; } }}#endif#endif#endif/* * V I D E O F O R L I N U X T W O I N I T I A L I Z A T I O N */static struct file_operations video_fops ={#if LINUX_VERSION_CODE >= 0x020403 owner: THIS_MODULE,#endif llseek: v4l2_video_llseek, read: video_read, write: video_write, poll: video_poll, ioctl: video_ioctl, mmap: video_mmap, open: video_open, release: video_release};static struct file_operations v4l2_fops ={ llseek: v4l2_video_llseek, read: v4l2_video_read, write: v4l2_video_write, poll: v4l2_video_poll, ioctl: v4l2_video_ioctl, mmap: v4l2_video_mmap, open: v4l2_video_open, release: v4l2_video_release};/* * Initialize Video for Linux Two */ #ifdef CONFIG_DEVFS_FS#define REGISTER_CHRDEV devfs_register_chrdev#define UNREGISTER_CHRDEV devfs_unregister_chrdev#else#define REGISTER_CHRDEV register_chrdev#define UNREGISTER_CHRDEV unregister_chrdev#endifstatic intvideodev_register_chrdev(int interface /* 1 or 2 */){ int major[3]; char *name; struct file_operations *fops; major[1] = VIDEO_MAJOR; major[2] = v4l2_major; name = (interface == 1) ? "v4l1" : "v4l2"; fops = (interface == 1) ? &video_fops : &v4l2_fops; if (interface == 1) printk(KERN_INFO"Video for Linux One (2.2.16)." " Major device: %d\n", major[1]); if (interface == 2) printk(KERN_INFO"Video for Linux Two (V%d.%d)." " Major device: %d\n", V4L2_MAJOR_VERSION, V4L2_MINOR_VERSION, major[2]); if (major[1] == major[2]) { if (interface == 2) return 0; name = "v4l1/2"; fops = &v4l2_fops; } if (REGISTER_CHRDEV(major[interface], name, fops)) { printk("Unable to get major %d for %s\n", major[interface], name); return -EIO; } return 0;}static intvideodev_unregister_chrdev(int interface /* 1 or 2 */){ int major[3]; char *name; major[1] = VIDEO_MAJOR; major[2] = v4l2_major; name = (interface == 1) ? "v4l1" : "v4l2"; if (major[1] == major[2]) { if (interface == 2) return 0; name = "v4l1/2"; } UNREGISTER_CHRDEV(major[interface], name); return 0;}int videodev_init(void){ int i; struct video_init *vfli = video_init_list; i = videodev_register_chrdev(1); if (i == 0) i = videodev_register_chrdev(2); if (i) return i; /* make sure there's a way to tell if a device is not there */ for (i = 0; i < V4L2_NUM_DEVICES; i++) v4l2_device[i] = NULL; for (i = 0; i < VIDEO_NUM_DEVICES; i++) video_device[i] = NULL;#ifdef CONFIG_PROC_FS#if LINUX_VERSION_CODE < 0x020300 proc_register(&proc_root, &video_proc_entry);#else /* 2.3 */ videodev_proc_create ();#endif#endif masterclock = NULL; while(vfli->init!=NULL) { vfli->init(vfli); vfli++; } return 0;}#ifdef MODULE int init_module(void){ return videodev_init();}void cleanup_module(void){#ifdef CONFIG_PROC_FS#if LINUX_VERSION_CODE < 0x020300 proc_unregister(&proc_root, video_proc_entry.low_ino);#else /* 2.3 */ videodev_proc_destroy ();#endif#endif /* CONFIG_PROC_FS */ videodev_unregister_chrdev(1); videodev_unregister_chrdev(2);}#endif/* * * V 4 L 2 D R I V E R H E L P E R A P I * */voidv4l2_version(int *major, int *minor){ *major = V4L2_MAJOR_VERSION; *minor = V4L2_MINOR_VERSION;}intv4l2_major_number(void){ return v4l2_major;}struct v4l2_device *v4l2_device_from_minor(int minor){ if (minor < 0 || minor >= V4L2_NUM_DEVICES) return NULL; return v4l2_device[minor];}struct v4l2_device *v4l2_device_from_file(struct file *file){ if (file == NULL) return NULL; return v4l2_device_from_minor(MINOR(file->f_dentry->d_inode->i_rdev));}void *v4l2_openid_from_file(struct file *file){ if (file == NULL) return NULL; return file->private_data;}#if LINUX_VERSION_CODE >= 0x020300struct page *kvirt_to_pa(unsigned long adr){ struct page *ret = NULL; pmd_t *pmd; pte_t *pte; pgd_t *pgd; pgd = pgd_offset_k(adr); if (!pgd_none(*pgd)) { pmd = pmd_offset(pgd, adr); if (!pmd_none(*pmd)) { pte = pte_offset(pmd, adr); if (pte_present(*pte)) { ret = pte_page(*pte); } } } return ret;}/* Useful for using vmalloc()ed memory as DMA target */unsigned long v4l2_vmalloc_to_bus(void *virt){ struct page *page; unsigned long kva, ret; page = kvirt_to_pa((unsigned long) virt); kva = ((unsigned long)page_address(page)) | (((unsigned long) virt) & (PAGE_SIZE - 1)); ret = virt_to_bus((void *) kva); return ret;}/* Useful for a nopage handler when mmap()ing vmalloc()ed memory */struct page *v4l2_vmalloc_to_page(void *virt){ struct page *page; page = kvirt_to_pa((unsigned long) virt); return page;}#else /* 2.2 */static struct mm_struct *find_init_mm(void){ static struct mm_struct *mm; struct task_struct *p; if (mm) return mm; for (p = current; p && (p = p->next_task) != current; ) if (p->pid == 0) break; mm = (p) ? p->mm : NULL; return mm;}/* Useful for using vmalloc()ed memory as DMA target */unsigned longv4l2_vmalloc_to_bus(void *virt){ pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long a = (unsigned long)virt; struct mm_struct *mm = find_init_mm(); if (mm == NULL || pgd_none(*(pgd = pgd_offset(mm, a))) || pmd_none(*(pmd = pmd_offset(pgd, a))) || pte_none(*(pte = pte_offset(pmd, a)))) return 0; return virt_to_bus((void *)pte_page(*pte)) + (a & (PAGE_SIZE - 1));}/* Useful for a nopage handler when mmap()ing vmalloc()ed memory */unsigned longv4l2_vmalloc_to_page(void *virt){ pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long a = (unsigned long)virt; struct mm_struct *mm = find_init_mm(); if (mm == NULL || pgd_none(*(pgd = pgd_offset(current->mm, a))) || pmd_none(*(pmd = pmd_offset(pgd, a))) || pte_none(*(pte = pte_offset(pmd, a)))) return 0; return pte_page(*pte);}#endif /* 2.2 *//* * Simple queue management */static rwlock_t rw_lock_unlocked = RW_LOCK_UNLOCKED;void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -