近日游玩看了v4l2-core相关的v4l2-dev.c,uvc_v4l2.c有些想法,特写下.、
#ifndef _V4L2_DEVICE_H
#define _V4L2_DEVICE_H
struct v4l2_file_operations
{
struct module*owner;
size_t (*read)(struct file*,char __user*,size_t ,loff_t*);
size_t (*write)(struct file*,char __user*,size_t ,loff_t*);
unsigned int (*poll)(struct file*,struct poll_table_struct*);
long (*unlocked_ioctl)(struct file*,unsigned int,unsigned long);
int (*mmap)(struct file*,struct vm_area_struct*);
int (*open)(struct file*);
int (*release)(struct file*);
};
struct v4l2_ioctl_ops
{
int (*videoc_reqbufs)(struct file*file,void*fh,struct v4l2_requestbuffers*b);
int (*videoc_querybuf)(struct file*file,void*fh,struct v4l2_buffer*b);
int (*videoc_qbuf)(struct file*file,void*fh,struct v4l2_buffer*b);
int (*vidioc_dqbuf)(struct file*file,void*fh,struct v4l2_buffer*b);
int (*vidioc_streamon)(struct file*file,void*fh,enum v4l2_buf_type i);
int (*vidioc_streamoff)(struct file*file,void*fh,enum v4l2_buf_type i);
int (*vidioc_subcribe_event)(struct v4l2_fh*fh,const struct v4l2_event_subscription*sub);
int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh,const struct v4l2_event_subscription *sub);
};
struct video_device
{
struct cdev*cdev;
const struct v4l2_file_operations*fops;
struct device dev;
char name[32];
int minor;
int num;
unsigned long flags;
int index;
spinlock_t fh_lock;
void (*release)(struct video_device*vdev);
const struct v4l2_ioctl_ops*ioctl_ops;
};
struct uvc_device
{
struct video_device vdev;
};
#define VFL_TYPE_GRABBER 0
extern int video_register_device(struct video_device*vdev,int type,int nr);
extern void video_unregister_device(struct video_device*vdev);
#endif
#include "common.h"
static struct uvc_device*uvc_device = NULL;
#define VIDEO_MAJOR 81
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
#define to_video_device(cd) container_of(cd,struct video_device,dev)
static struct video_device*video_device[VIDEO_NUM_DEVICES];
static dev_t dev = MKDEV(VIDEO_MAJOR, 0);
struct video_device*video_devdata(struct file*file)
{
return video_device[iminor(file_inode(file))];
}
static struct class video_class = {
.name = VIDEO_NAME,
};
static ssize_t v4l2_read(struct file*filp,char __user*buf,size_t sz,
loff_t*off)
{
int ret = -ENODEV;
struct video_device*vdev = video_devdata(filp);
if(!vdev->fops->read)
{
printk("v4l2_read\n");
return -EINVAL;
}
printk("v4l2_read 36\n");
ret = vdev->fops->read(filp,buf,sz,off);
return ret;
}
static ssize_t v4l2_write(struct file*filp,const char __user*buf,
size_t sz,loff_t*off)
{
struct video_device*vdev = video_devdata(filp);
int ret = -ENODEV;
if(!vdev->fops->write)
return -EINVAL;
printk("v4l2_write 50\n");
ret = vdev->fops->write(filp,buf,sz,off);
return ret;
}
static unsigned v4l2_poll(struct file *file, poll_table *wait)
{
struct video_device*vdev = video_devdata(file);
unsigned int res = POLLERR | POLLHUP;
if(!vdev->fops->poll)
return DEFAULT_POLLMASK;
res = vdev->fops->poll(file,wait);
return res;
}
static long v4l2_ioctl(struct file*filp,unsigned int cmd,unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if(vdev->fops->unlocked_ioctl)
{
ret = vdev->fops->unlocked_ioctl(filp,cmd,arg);
}
else
{
ret = -ENOTTY;
}
return ret;
}
static int v4l2_open(struct inode*inode,struct file*filp)
{
struct video_device*vdev;
int ret = 0;
vdev = video_devdata(filp);
printk("v4l2_open 87\n");
if(vdev->fops->open)
{
ret = vdev->fops->open(filp);
}
else
{
ret = -ENODEV;
}
return ret;
}
static int v4l2_mmap(struct file*filp,struct vm_area_struct*vm)
{
struct video_device*vdev = video_devdata(filp);
int ret = -ENODEV;
if(!vdev->fops->mmap)
return -ENODEV;
ret = vdev->fops->mmap(filp,vm);
return ret;
}
static int v4l2_release(struct inode*inode,struct file*filp)
{
struct video_device*vdev = video_devdata(filp);
int ret = 0;
if(vdev->fops->release)
ret = vdev->fops->release(filp);
return 0;
}
static const struct file_operations v4l2_fops =
{
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
.release = v4l2_release,
.poll = v4l2_poll,
};
static int uvc_v4l2_open(struct file*file)
{
struct video_device*vdev = video_devdata(file);
printk("uvc_v4l2_open 133\n");
return 0;
}
static int uvc_v4l2_release(struct file*file)
{
struct video_device *vdev = video_devdata(file);
printk("uvc_v4l2_release 140\n");
return 0;
}
static int uvc_v4l2_mmap(struct file*file,struct vm_area_struct*vm)
{
struct video_device *vdev = video_devdata(file);
printk("uvc_v4l2_mmap 147\n");
return 0;
}
static unsigned uvc_v4l2_poll(struct file *file, poll_table *wait)
{
struct video_device*vdev = video_devdata(file);
printk("uvc_v4l2_poll 155\n");
return 0;
}
const struct v4l2_file_operations uvc_v4l2_fops =
{
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
};
static void v4l2_device_release(struct device*d)
{
struct video_device*vdev = to_video_device(d);
video_device[vdev->minor] = NULL;
printk("vdev->minor is %d\n",vdev->minor);
cdev_del(vdev->cdev);
vdev->cdev = NULL;
}
int video_register_device(struct video_device*vdev,int type,int nr)
{
int ret;
int minor_offset = 0;
int minr_cnt = 64;
const char*name_base;
vdev->minor = -1;
name_base = "video";
vdev->cdev = NULL;
vdev->minor = nr -1;
vdev->num = nr-1;
video_device[vdev->minor] = vdev;
vdev->cdev = cdev_alloc();
if (vdev->cdev == NULL) {
ret = -ENOMEM;
return ret;
}
vdev->cdev->ops = &v4l2_fops;
ret = cdev_add(vdev->cdev,MKDEV(VIDEO_MAJOR,vdev->minor),1);
if (ret < 0)
{
printk("%s: cdev_add failed\n", __func__);
kfree(vdev->cdev);
vdev->cdev = NULL;
return ret;
}
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR,vdev->minor);
printk("vdev->num is %d\n",vdev->num);
dev_set_name(&vdev->dev,"%s%d",name_base,vdev->num);
ret = device_register(&vdev->dev);
vdev->dev.release = v4l2_device_release;
return 0;
}
void video_unregister_device(struct video_device*vdev)
{
printk("video_unregister_device 77\n");
device_unregister(&vdev->dev);
class_unregister(&video_class);
unregister_chrdev_region(dev,VIDEO_NUM_DEVICES);
}
static int videodev_init(void)
{
int ret;
printk("register_chrdev_region Linux video capture interface: v2.00\n");
ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
if (ret < 0) {
printk("videodev: unable to get major %d\n",VIDEO_MAJOR);
return ret;
}
ret = class_register(&video_class);
if (ret < 0) {
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
printk("video_dev: class_register failed\n");
return -EIO;
}
return 0;
}
static int __init globalmem_platform_init(void)
{
uvc_device = kzalloc(sizeof(*uvc_device),GFP_KERNEL);
if(uvc_device == NULL)
{
return -ENOMEM;
}
videodev_init();
uvc_device->vdev.fops = &uvc_v4l2_fops;
uvc_device->vdev.ioctl_ops = NULL;
video_register_device(&uvc_device->vdev,VFL_TYPE_GRABBER,1);
return 0;
}
static void __exit globalmem_platform_exit(void)
{
video_unregister_device(&uvc_device->vdev);
kfree(uvc_device);
return ;
}
module_init(globalmem_platform_init);
module_exit(globalmem_platform_exit);
MODULE_LICENSE("GPL");