从零写USB摄像头驱动之实现数据传输1_框架

来源:互联网 发布:驯化狼 知乎 编辑:程序博客网 时间:2024/06/15 00:24

dmesg命令缺点:
1 每次都去要输入查看
2 驱动程序有问题导致内核崩溃,无法私有dmesg命令

A. 设置ubuntu让它从串口0输出printk信息

a. 设置vmware添加serial port, 使用文件作为串口
b. 启动ubuntu,修改/etc/default/grub

vi  /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT=""GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8"
sudo update-grubsudo reboot

c. ubuntu禁止root用户登录
先修改root密码: sudo passwd root
然后执行”su root”就可以用root登录了
d. echo "8 4 1 7" > /proc/sys/kernel/printk
完成以上四步就可以在输出文件看到内核的信息

B. 写代码:

1.构造一个usb_driver2.设置   probe:        2.1. 分配video_device:video_device_alloc        2.2. 设置           .fops           .ioctl_ops (里面需要设置11项)           如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops        2.3. 注册: video_register_device      3.注册: usb_register

注:id_table: 表示支持哪些USB设备

参考 myvivi.c写myuvc.c

static int myuvc_probe(struct usb_interface *intf,             const struct usb_device_id *id){    ...    if(cnt == 2) //myuvc_ids有VideoControl Interface、VideoStreaming Interface,在第二个注册    {        /*1.分配一个video_device结构体*/        myuvc_vdev =video_device_alloc();      /*2.设置*/      /*2.1*/      myuvc_vdev->release =myuvc_release;      /*2.2*/      myuvc_vdev->fops =&myuvc_fops;      /*2.3*/      myuvc_vdev->ioctl_ops =&myuvc_ioctl_ops;      /*3.注册*/      video_register_device(myuvc_vdev,VFL_TYPE_GRABBER, -1);     }}

注:缺少myuvc_release将无法注册,v4l2-dev.c

 /* the release callback MUST be present */        if (WARN_ON(!vdev->release))                return -EINVAL;

写一个空函数

/**写一个myuvc_release空函数/             static void myuvc_release(struct video_device *vdev){}   
static void myuvc_disconnect(struct usb_interface *intf){    static int cnt = 0;    printk("myuvc_disconnect : cnt = %d\n", cnt++);    if (cnt == 2)    {        video_unregister_device(myuvc_vdev);        video_device_release(myuvc_vdev);    } }  

linux驱动之–fops的关联
http://blog.csdn.net/zssmcu/article/details/6746770

static const struct v4l2_file_operations myuvc_fops = {    .owner      = THIS_MODULE,    .open       = myuvc_open,    .release    = myuvc_close,    .mmap       = myuvc_mmap,    .ioctl      = video_ioctl2, /* V4L2 ioctl handler */    .poll       = myuvc_poll,};

这里完成框架性的东西,不写内容

static int myuvc_open(struct file *file){    return 0;}
myuvc_fops    video_ioctl2        __video_do_ioctl            v4l2_ioctl_ops  找到v4l2_ioctl_ops结构体
static const struct v4l2_ioctl_ops myuvc_ioctl_ops = {        // 表示它是一个摄像头设备        .vidioc_querycap      = myuvc_vidioc_querycap,//查询性能        /* 用于列举、获得、测试、设置摄像头的数据的格式 */        .vidioc_enum_fmt_vid_cap  = myuvc_vidioc_enum_fmt_vid_cap,        .vidioc_g_fmt_vid_cap     = myuvc_vidioc_g_fmt_vid_cap,        .vidioc_try_fmt_vid_cap   = myuvc_vidioc_try_fmt_vid_cap,        .vidioc_s_fmt_vid_cap     = myuvc_vidioc_s_fmt_vid_cap,        /* 缓冲区操作: 申请/查询/放入队列/取出队列 */        .vidioc_reqbufs       = myuvc_vidioc_reqbufs,        .vidioc_querybuf      = myuvc_vidioc_querybuf,        .vidioc_qbuf          = myuvc_vidioc_qbuf,        .vidioc_dqbuf         = myuvc_vidioc_dqbuf,        // 启动/停止        .vidioc_streamon      = myuvc_vidioc_streamon,        .vidioc_streamoff     = myuvc_vidioc_streamoff,   };

注:整体流程
应用程程序(app)打开设备(调用myuvc_open),确定(调用myuvc_vidioc_querycap)它是视频设备,获取格式信息,申请缓冲区,查询缓冲区信息,将缓冲区映射到用户空间,把缓冲区放入队列,
启动传输。

下面是关于myuvc_ioctl_ops结构体中各个单元的实现

/* A2 查询性能*/static int myuvc_vidioc_querycap(struct file *file, void  *priv,                    struct v4l2_capability *cap){    return 0;}/* A3 列举支持哪种格式 */static int myuvc_vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,                    struct v4l2_fmtdesc *f){    return 0;}/* A4 返回当前所使用的格式 */static int myuvc_vidioc_g_fmt_vid_cap(struct file *file, void *priv,                    struct v4l2_format *f){    return (0);}/* A5 测试驱动程序是否支持某种格式 */static int myuvc_vidioc_try_fmt_vid_cap(struct file *file, void *priv,            struct v4l2_format *f){    return 0;}/* A6 */static int myuvc_vidioc_s_fmt_vid_cap(struct file *file, void *priv,                    struct v4l2_format *f){    return 0;}/* A7 APP调用该ioctl让驱动程序分配若干个缓存, APP将从这些缓存中读到视频数据 */static int myuvc_vidioc_reqbufs(struct file *file, void *priv,              struct v4l2_requestbuffers *p){    return 0;}/* A8 查询缓存状态, 比如地址信息(APP可以用mmap进行映射)*/static int myuvc_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p){    return 0;}/* A10 把缓冲区放入队列, 底层的硬件操作函数将会把数据放入这个队列的缓存 */static int myuvc_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p){    return 0;}/* A11 启动传输 */static int myuvc_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){    return 0;}/* A13 APP通过poll/select确定有数据后, 把缓存从队列中取出来 */static int myuvc_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p){    return 0;}/* * A14 之前已经通过mmap映射了缓存, APP可以直接读数据 * A15 再次调用myuvc_vidioc_qbuf把缓存放入队列 * A16 poll... *//* A17 停止 */static int myuvc_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i){    return 0;}

插上摄像头,ls /dev/vid*
这里写图片描述
linux系统自动装载了摄像

sudo rmmod  uvcvideo
su rootinsmod myuvc.koecho "8 4 1 7" > /proc/sys/kernel/printk

可以在输出文件看到内核的信息
这里写图片描述

阅读全文
0 0
原创粉丝点击