自己写的uvc驱动支持IP2977/ip2970

  1. /* 作者: 453411484@qq.com  
  2.  * 此驱动程序是基于linux2.6.31.14内核 
  3.  * 上一篇自己写的uvc驱动程序是针对环宇飞扬6190来写的,有一些缺点,这些缺点在本次的驱动 
  4.  * 中进行了修改此uvc驱动是针对IP2977进行了支持,根据IP2977芯片厂商提供的修改手册进行了修改。 
  5.  * 此驱动程序虽然支持IP2977摄像头,但是显示效果不太好,此驱动只是针对学习使用。 
  6.  */  
  7.   
  8. #include <linux kernel="" h="">  
  9. #include <linux list="" h="">  
  10. #include <linux module="" h="">  
  11. #include <linux usb="" h="">  
  12. #include <linux videodev2="" h="">  
  13. #include <linux vmalloc="" h="">  
  14. #include <linux wait="" h="">  
  15. #include <linux mm="" h="">  
  16. #include <asm atomic="" h="">  
  17. #include <asm unaligned="" h="">  
  18.   
  19. #include <media v4l2-common="" h="">  
  20. #include <media v4l2-ioctl="" h="">  
  21. #include <media videobuf-core="" h="">  
  22.   
  23. #include "uvcvideo.h"  
  24.   
  25. /* 参考 drivers/media/video/uvc */  
  26.   
  27. #define MYUVC_URBS 5  
  28.   
  29. /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */  
  30. #define UVC_STREAM_EOH  (1 << 7)  
  31. #define UVC_STREAM_ERR  (1 << 6)  
  32. #define UVC_STREAM_STI  (1 << 5)  
  33. #define UVC_STREAM_RES  (1 << 4)  
  34. #define UVC_STREAM_SCR  (1 << 3)  
  35. #define UVC_STREAM_PTS  (1 << 2)  
  36. #define UVC_STREAM_EOF  (1 << 1)  
  37. #define UVC_STREAM_FID  (1 << 0)  
  38.   
  39.   
  40. struct myuvc_streaming_control {  
  41.     __u16 bmHint;  
  42.     __u8  bFormatIndex;  
  43.     __u8  bFrameIndex;  
  44.     __u32 dwFrameInterval;  
  45.     __u16 wKeyFrameRate;  
  46.     __u16 wPFrameRate;  
  47.     __u16 wCompQuality;  
  48.     __u16 wCompWindowSize;  
  49.     __u16 wDelay;  
  50.     __u32 dwMaxVideoFrameSize;  
  51.     __u32 dwMaxPayloadTransferSize;  
  52.     __u32 dwClockFrequency;  
  53.     __u8  bmFramingInfo;  
  54.     __u8  bPreferedVersion;  
  55.     __u8  bMinVersion;  
  56.     __u8  bMaxVersion;  
  57. };  
  58.   
  59.   
  60.   
  61. struct frame_desc {  
  62.     int width;  
  63.     int height;  
  64. };  
  65.   
  66. /* 参考uvc_video_queue定义一些结构体 */  
  67. struct myuvc_buffer {      
  68.     struct v4l2_buffer buf;  
  69.     int state;  
  70.     int vma_use_count; /* 表示是否已经被mmap */  
  71.     wait_queue_head_t wait;  /* APP要读某个缓冲区,如果无数据,在此休眠 */  
  72.     struct list_head stream;  
  73.     struct list_head irq;      
  74. };  
  75.   
  76. struct myuvc_queue {  
  77.     void *mem;  
  78.     int count;  
  79.     int buf_size;      
  80.     struct myuvc_buffer buffer[32];  
  81.   
  82.     struct urb *urb[32];  
  83.     char *urb_buffer[32];  
  84.     dma_addr_t urb_dma[32];  
  85.     unsigned int urb_size;  
  86.   
  87.     struct list_head mainqueue;   /* 供APP消费用 */  
  88.     struct list_head irqqueue;    /* 供底层驱动生产用 */  
  89. };  
  90.   
  91. static struct myuvc_queue myuvc_queue;  
  92.   
  93. static struct video_device *myuvc_vdev;  
  94. static struct usb_device *myuvc_udev;  
  95.   
  96. static int myuvc_bEndpointAddress = 0x82;  
  97. static int myuvc_streaming_intf;  
  98. static int myuvc_control_intf;  
  99. static struct v4l2_format myuvc_format;  
  100.   
  101. static struct frame_desc frames[] = { {640, 480}, {320, 240}, {160, 120}};  
  102. static int frame_idx = 1;  
  103. static int bBitsPerPixel = 0; /* lsusb -v -d 0x1e4e:  "bBitsPerPixel" */  
  104. static int uvc_version = 0x0100; /* lsusb -v -d 0x1b3b: bcdUVC */  
  105.   
  106. static int ProcessingUnitID = 3;  /* lsusb -v -d 0x1b3b: PROCESSING_UNIT */  
  107.   
  108. /* 以后再设置 */  
  109. static int wMaxPacketSize = 800;  
  110. static int myuvc_streaming_bAlternateSetting = 5;  
  111. static int dwMaxVideoFrameSize = 77312;  
  112.   
  113. static struct myuvc_streaming_control myuvc_params;  
  114.   
  115. static int last_fid = -1;  
  116.   
  117. /* A2 参考 uvc_v4l2_do_ioctl */  
  118. static int myuvc_vidioc_querycap(struct file *file, void  *priv,  
  119.                     struct v4l2_capability *cap)  
  120. {      
  121.     memset(cap, 0, sizeof *cap);  
  122.     strcpy(cap->driver, "myuvc");  
  123.     strcpy(cap->card, "myuvc");  
  124.     cap->version = 1;  
  125.       
  126.     cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;  
  127.    
  128.     return 0;  
  129. }  
  130.   
  131. /* A3 列举支持哪种格式 
  132.  * 参考: uvc_fmts 数组 
  133.  */  
  134. static int myuvc_vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,  
  135.                     struct v4l2_fmtdesc *f)  
  136. {  
  137.     /* 人工查看描述符可知我们用的摄像头只支持1种格式 */  
  138.     if (f->index >= 1)  
  139.         return -EINVAL;  
  140.   
  141.     strcpy(f->description, "MJPEG");  
  142.     f->pixelformat = V4L2_PIX_FMT_MJPEG;      
  143.     //f->flags       = ;  
  144.     f->type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  145.       
  146.     return 0;  
  147. }  
  148.   
  149. /* A4 返回当前所使用的格式 */  
  150. static int myuvc_vidioc_g_fmt_vid_cap(struct file *file, void *priv,  
  151.                     struct v4l2_format *f)  
  152. {  
  153.     memcpy(f, &myuvc_format, sizeof(myuvc_format));  
  154.     return (0);  
  155. }  
  156.   
  157. /* A5 测试驱动程序是否支持某种格式, 强制设置该格式  
  158.  * 参考: uvc_v4l2_try_format 
  159.  *       myvivi_vidioc_try_fmt_vid_cap 
  160.  */  
  161. static int myuvc_vidioc_try_fmt_vid_cap(struct file *file, void *priv,  
  162.             struct v4l2_format *f)  
  163. {  
  164.     if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)  
  165.     {  
  166.         return -EINVAL;  
  167.     }  
  168.   
  169.     if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)  
  170.         return -EINVAL;  
  171.       
  172.     /* 调整format的width, height,  
  173.      * 计算bytesperline, sizeimage 
  174.      */  
  175.   
  176.     /* 人工查看描述符, 确定支持哪几种分辨率 */  
  177.     f->fmt.pix.width  = frames[frame_idx].width;  
  178.     f->fmt.pix.height = frames[frame_idx].height;  
  179.   
  180.     /* 对于MJPEG数据类型来说,bBitsPerPixel是无法知道的。因此我们设为0 */  
  181.     f->fmt.pix.bytesperline =  
  182.         (f->fmt.pix.width * bBitsPerPixel) >> 3;  
  183.       
  184.     /* 一帧数据最大为dwMaxVideoFrameSize=77312,是由确定带宽时确定出来的。 */  
  185.     f->fmt.pix.sizeimage = dwMaxVideoFrameSize;  
  186.   
  187.     f->fmt.pix.field      = V4L2_FIELD_NONE;  
  188.     /* 由描述符bColorPrimaries  1 (BT.709,sRGB)可知 */  
  189.     f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;  
  190.     f->fmt.pix.priv       = 0;       /* private data, depends on pixelformat */  
  191.       
  192.     return 0;  
  193. }  
  194.   
  195. /* A6 参考 myvivi_vidioc_s_fmt_vid_cap */  
  196. static int myuvc_vidioc_s_fmt_vid_cap(struct file *file, void *priv,  
  197.                     struct v4l2_format *f)  
  198. {  
  199.     int ret = myuvc_vidioc_try_fmt_vid_cap(file, NULL, f);  
  200.     if (ret < 0)  
  201.         return ret;  
  202.   
  203.     memcpy(&myuvc_format, f, sizeof(myuvc_format));  
  204.       
  205.     return 0;  
  206. }  
  207.   
  208. static int myuvc_free_buffers(void)  
  209. {  
  210.     if (myuvc_queue.mem)  
  211.     {  
  212.         vfree(myuvc_queue.mem);  
  213.         memset(&myuvc_queue, 0, sizeof(myuvc_queue));  
  214.         myuvc_queue.mem = NULL;  
  215.     }  
  216.     return 0;  
  217. }  
  218.   
  219. /* A7 APP调用该ioctl让驱动程序分配若干个缓存, APP将从这些缓存中读到视频数据  
  220.  * 参考: uvc_alloc_buffers 
  221.  */  
  222. static int myuvc_vidioc_reqbufs(struct file *file, void *priv,  
  223.               struct v4l2_requestbuffers *p)  
  224. {  
  225.     int nbuffers = p->count;  
  226.     int bufsize  = PAGE_ALIGN(myuvc_format.fmt.pix.sizeimage);  
  227.     unsigned int i;  
  228.     void *mem = NULL;  
  229.     int ret;  
  230.   
  231.     if ((ret = myuvc_free_buffers()) < 0)  
  232.         goto done;  
  233.   
  234.     /* Bail out if no buffers should be allocated. */  
  235.     if (nbuffers == 0)  
  236.         goto done;  
  237.   
  238.     /* Decrement the number of buffers until allocation succeeds. */  
  239.     for (; nbuffers > 0; --nbuffers) {  
  240.         mem = vmalloc_32(nbuffers * bufsize);  
  241.         if (mem != NULL)  
  242.             break;  
  243.     }  
  244.   
  245.     if (mem == NULL) {  
  246.         ret = -ENOMEM;  
  247.         goto done;  
  248.     }  
  249.   
  250.     /* 这些缓存是一次性作为一个整体来分配的 */  
  251.     memset(&myuvc_queue, 0, sizeof(myuvc_queue));  
  252.   
  253.     INIT_LIST_HEAD(&myuvc_queue.mainqueue);  
  254.     INIT_LIST_HEAD(&myuvc_queue.irqqueue);  
  255.   
  256.     for (i = 0; i < nbuffers; ++i) {  
  257.         myuvc_queue.buffer[i].buf.index = i;  
  258.         myuvc_queue.buffer[i].buf.m.offset = i * bufsize;  
  259.         myuvc_queue.buffer[i].buf.length = myuvc_format.fmt.pix.sizeimage;  
  260.         myuvc_queue.buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  261.         myuvc_queue.buffer[i].buf.sequence = 0;  
  262.         myuvc_queue.buffer[i].buf.field = V4L2_FIELD_NONE;  
  263.         myuvc_queue.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值