日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

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

發(fā)布時(shí)間:2023/12/14 c/c++ 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己写的uvc驱动支持IP2977/ip2970 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
  • /*?作者:?453411484@qq.com??
  • ?*?此驅(qū)動(dòng)程序是基于linux2.6.31.14內(nèi)核?
  • ?*?上一篇自己寫的uvc驅(qū)動(dòng)程序是針對環(huán)宇飛揚(yáng)6190來寫的,有一些缺點(diǎn),這些缺點(diǎn)在本次的驅(qū)動(dòng)?
  • ?*?中進(jìn)行了修改此uvc驅(qū)動(dòng)是針對IP2977進(jìn)行了支持,根據(jù)IP2977芯片廠商提供的修改手冊進(jìn)行了修改。?
  • ?*?此驅(qū)動(dòng)程序雖然支持IP2977攝像頭,但是顯示效果不太好,此驅(qū)動(dòng)只是針對學(xué)習(xí)使用。?
  • ?*/??
  • ??
  • #include?<linux?kernel=""?h="">??
  • #include?<linux?list=""?h="">??
  • #include?<linux?module=""?h="">??
  • #include?<linux?usb=""?h="">??
  • #include?<linux?videodev2=""?h="">??
  • #include?<linux?vmalloc=""?h="">??
  • #include?<linux?wait=""?h="">??
  • #include?<linux?mm=""?h="">??
  • #include?<asm?atomic=""?h="">??
  • #include?<asm?unaligned=""?h="">??
  • ??
  • #include?<media?v4l2-common=""?h="">??
  • #include?<media?v4l2-ioctl=""?h="">??
  • #include?<media?videobuf-core=""?h="">??
  • ??
  • #include?"uvcvideo.h"??
  • ??
  • /*?參考?drivers/media/video/uvc?*/??
  • ??
  • #define?MYUVC_URBS?5??
  • ??
  • /*?Values?for?bmHeaderInfo?(Video?and?Still?Image?Payload?Headers,?2.4.3.3)?*/??
  • #define?UVC_STREAM_EOH??(1?<<?7)??
  • #define?UVC_STREAM_ERR??(1?<<?6)??
  • #define?UVC_STREAM_STI??(1?<<?5)??
  • #define?UVC_STREAM_RES??(1?<<?4)??
  • #define?UVC_STREAM_SCR??(1?<<?3)??
  • #define?UVC_STREAM_PTS??(1?<<?2)??
  • #define?UVC_STREAM_EOF??(1?<<?1)??
  • #define?UVC_STREAM_FID??(1?<<?0)??
  • ??
  • ??
  • struct?myuvc_streaming_control?{??
  • ????__u16?bmHint;??
  • ????__u8??bFormatIndex;??
  • ????__u8??bFrameIndex;??
  • ????__u32?dwFrameInterval;??
  • ????__u16?wKeyFrameRate;??
  • ????__u16?wPFrameRate;??
  • ????__u16?wCompQuality;??
  • ????__u16?wCompWindowSize;??
  • ????__u16?wDelay;??
  • ????__u32?dwMaxVideoFrameSize;??
  • ????__u32?dwMaxPayloadTransferSize;??
  • ????__u32?dwClockFrequency;??
  • ????__u8??bmFramingInfo;??
  • ????__u8??bPreferedVersion;??
  • ????__u8??bMinVersion;??
  • ????__u8??bMaxVersion;??
  • };??
  • ??
  • ??
  • ??
  • struct?frame_desc?{??
  • ????int?width;??
  • ????int?height;??
  • };??
  • ??
  • /*?參考uvc_video_queue定義一些結(jié)構(gòu)體?*/??
  • struct?myuvc_buffer?{??????
  • ????struct?v4l2_buffer?buf;??
  • ????int?state;??
  • ????int?vma_use_count;?/*?表示是否已經(jīng)被mmap?*/??
  • ????wait_queue_head_t?wait;??/*?APP要讀某個(gè)緩沖區(qū),如果無數(shù)據(jù),在此休眠?*/??
  • ????struct?list_head?stream;??
  • ????struct?list_head?irq;??????
  • };??
  • ??
  • struct?myuvc_queue?{??
  • ????void?*mem;??
  • ????int?count;??
  • ????int?buf_size;??????
  • ????struct?myuvc_buffer?buffer[32];??
  • ??
  • ????struct?urb?*urb[32];??
  • ????char?*urb_buffer[32];??
  • ????dma_addr_t?urb_dma[32];??
  • ????unsigned?int?urb_size;??
  • ??
  • ????struct?list_head?mainqueue;???/*?供APP消費(fèi)用?*/??
  • ????struct?list_head?irqqueue;????/*?供底層驅(qū)動(dòng)生產(chǎn)用?*/??
  • };??
  • ??
  • static?struct?myuvc_queue?myuvc_queue;??
  • ??
  • static?struct?video_device?*myuvc_vdev;??
  • static?struct?usb_device?*myuvc_udev;??
  • ??
  • static?int?myuvc_bEndpointAddress?=?0x82;??
  • static?int?myuvc_streaming_intf;??
  • static?int?myuvc_control_intf;??
  • static?struct?v4l2_format?myuvc_format;??
  • ??
  • static?struct?frame_desc?frames[]?=?{{640,?480},?{320,?240},?{160,?120}};??
  • static?int?frame_idx?=?1;??
  • static?int?bBitsPerPixel?=?0;?/*?lsusb?-v?-d?0x1e4e:??"bBitsPerPixel"?*/??
  • static?int?uvc_version?=?0x0100;?/*?lsusb?-v?-d?0x1b3b:?bcdUVC?*/??
  • ??
  • static?int?ProcessingUnitID?=?3;??/*?lsusb?-v?-d?0x1b3b:?PROCESSING_UNIT?*/??
  • ??
  • /*?以后再設(shè)置?*/??
  • static?int?wMaxPacketSize?=?800;??
  • static?int?myuvc_streaming_bAlternateSetting?=?5;??
  • static?int?dwMaxVideoFrameSize?=?77312;??
  • ??
  • static?struct?myuvc_streaming_control?myuvc_params;??
  • ??
  • static?int?last_fid?=?-1;??
  • ??
  • /*?A2?參考?uvc_v4l2_do_ioctl?*/??
  • static?int?myuvc_vidioc_querycap(struct?file?*file,?void??*priv,??
  • ????????????????????struct?v4l2_capability?*cap)??
  • {??????
  • ????memset(cap,?0,?sizeof?*cap);??
  • ????strcpy(cap->driver,?"myuvc");??
  • ????strcpy(cap->card,?"myuvc");??
  • ????cap->version?=?1;??
  • ??????
  • ????cap->capabilities?=?V4L2_CAP_VIDEO_CAPTURE?|?V4L2_CAP_STREAMING;??
  • ???
  • ????return?0;??
  • }??
  • ??
  • /*?A3?列舉支持哪種格式?
  • ?*?參考:?uvc_fmts?數(shù)組?
  • ?*/??
  • static?int?myuvc_vidioc_enum_fmt_vid_cap(struct?file?*file,?void??*priv,??
  • ????????????????????struct?v4l2_fmtdesc?*f)??
  • {??
  • ????/*?人工查看描述符可知我們用的攝像頭只支持1種格式?*/??
  • ????if?(f->index?>=?1)??
  • ????????return?-EINVAL;??
  • ??
  • ????strcpy(f->description,?"MJPEG");??
  • ????f->pixelformat?=?V4L2_PIX_FMT_MJPEG;??????
  • ????//f->flags???????=?;??
  • ????f->type????????=?V4L2_BUF_TYPE_VIDEO_CAPTURE;??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?A4?返回當(dāng)前所使用的格式?*/??
  • static?int?myuvc_vidioc_g_fmt_vid_cap(struct?file?*file,?void?*priv,??
  • ????????????????????struct?v4l2_format?*f)??
  • {??
  • ????memcpy(f,?&myuvc_format,?sizeof(myuvc_format));??
  • ????return?(0);??
  • }??
  • ??
  • /*?A5?測試驅(qū)動(dòng)程序是否支持某種格式,?強(qiáng)制設(shè)置該格式??
  • ?*?參考:?uvc_v4l2_try_format?
  • ?*???????myvivi_vidioc_try_fmt_vid_cap?
  • ?*/??
  • static?int?myuvc_vidioc_try_fmt_vid_cap(struct?file?*file,?void?*priv,??
  • ????????????struct?v4l2_format?*f)??
  • {??
  • ????if?(f->type?!=?V4L2_BUF_TYPE_VIDEO_CAPTURE)??
  • ????{??
  • ????????return?-EINVAL;??
  • ????}??
  • ??
  • ????if?(f->fmt.pix.pixelformat?!=?V4L2_PIX_FMT_MJPEG)??
  • ????????return?-EINVAL;??
  • ??????
  • ????/*?調(diào)整format的width,?height,??
  • ?????*?計(jì)算bytesperline,?sizeimage?
  • ?????*/??
  • ??
  • ????/*?人工查看描述符,?確定支持哪幾種分辨率?*/??
  • ????f->fmt.pix.width??=?frames[frame_idx].width;??
  • ????f->fmt.pix.height?=?frames[frame_idx].height;??
  • ??
  • ????/*?對于MJPEG數(shù)據(jù)類型來說,bBitsPerPixel是無法知道的。因此我們設(shè)為0?*/??
  • ????f->fmt.pix.bytesperline?=??
  • ????????(f->fmt.pix.width?*?bBitsPerPixel)?>>?3;??
  • ??????
  • ????/*?一幀數(shù)據(jù)最大為dwMaxVideoFrameSize=77312,是由確定帶寬時(shí)確定出來的。?*/??
  • ????f->fmt.pix.sizeimage?=?dwMaxVideoFrameSize;??
  • ??
  • ????f->fmt.pix.field??????=?V4L2_FIELD_NONE;??
  • ????/*?由描述符bColorPrimaries??1?(BT.709,sRGB)可知?*/??
  • ????f->fmt.pix.colorspace?=?V4L2_COLORSPACE_SRGB;??
  • ????f->fmt.pix.priv???????=?0;???????/*?private?data,?depends?on?pixelformat?*/??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?A6?參考?myvivi_vidioc_s_fmt_vid_cap?*/??
  • static?int?myuvc_vidioc_s_fmt_vid_cap(struct?file?*file,?void?*priv,??
  • ????????????????????struct?v4l2_format?*f)??
  • {??
  • ????int?ret?=?myuvc_vidioc_try_fmt_vid_cap(file,?NULL,?f);??
  • ????if?(ret?<?0)??
  • ????????return?ret;??
  • ??
  • ????memcpy(&myuvc_format,?f,?sizeof(myuvc_format));??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • static?int?myuvc_free_buffers(void)??
  • {??
  • ????if?(myuvc_queue.mem)??
  • ????{??
  • ????????vfree(myuvc_queue.mem);??
  • ????????memset(&myuvc_queue,?0,?sizeof(myuvc_queue));??
  • ????????myuvc_queue.mem?=?NULL;??
  • ????}??
  • ????return?0;??
  • }??
  • ??
  • /*?A7?APP調(diào)用該ioctl讓驅(qū)動(dòng)程序分配若干個(gè)緩存,?APP將從這些緩存中讀到視頻數(shù)據(jù)??
  • ?*?參考:?uvc_alloc_buffers?
  • ?*/??
  • static?int?myuvc_vidioc_reqbufs(struct?file?*file,?void?*priv,??
  • ??????????????struct?v4l2_requestbuffers?*p)??
  • {??
  • ????int?nbuffers?=?p->count;??
  • ????int?bufsize??=?PAGE_ALIGN(myuvc_format.fmt.pix.sizeimage);??
  • ????unsigned?int?i;??
  • ????void?*mem?=?NULL;??
  • ????int?ret;??
  • ??
  • ????if?((ret?=?myuvc_free_buffers())?<?0)??
  • ????????goto?done;??
  • ??
  • ????/*?Bail?out?if?no?buffers?should?be?allocated.?*/??
  • ????if?(nbuffers?==?0)??
  • ????????goto?done;??
  • ??
  • ????/*?Decrement?the?number?of?buffers?until?allocation?succeeds.?*/??
  • ????for?(;?nbuffers?>?0;?--nbuffers)?{??
  • ????????mem?=?vmalloc_32(nbuffers?*?bufsize);??
  • ????????if?(mem?!=?NULL)??
  • ????????????break;??
  • ????}??
  • ??
  • ????if?(mem?==?NULL)?{??
  • ????????ret?=?-ENOMEM;??
  • ????????goto?done;??
  • ????}??
  • ??
  • ????/*?這些緩存是一次性作為一個(gè)整體來分配的?*/??
  • ????memset(&myuvc_queue,?0,?sizeof(myuvc_queue));??
  • ??
  • ????INIT_LIST_HEAD(&myuvc_queue.mainqueue);??
  • ????INIT_LIST_HEAD(&myuvc_queue.irqqueue);??
  • ??
  • ????for?(i?=?0;?i?<?nbuffers;?++i)?{??
  • ????????myuvc_queue.buffer[i].buf.index?=?i;??
  • ????????myuvc_queue.buffer[i].buf.m.offset?=?i?*?bufsize;??
  • ????????myuvc_queue.buffer[i].buf.length?=?myuvc_format.fmt.pix.sizeimage;??
  • ????????myuvc_queue.buffer[i].buf.type?=?V4L2_BUF_TYPE_VIDEO_CAPTURE;??
  • ????????myuvc_queue.buffer[i].buf.sequence?=?0;??
  • ????????myuvc_queue.buffer[i].buf.field?=?V4L2_FIELD_NONE;??
  • ????????myuvc_queue.buffer[i].buf.memory?=?V4L2_MEMORY_MMAP;??
  • ????????myuvc_queue.buffer[i].buf.flags?=?0;??
  • ????????myuvc_queue.buffer[i].state?????=?VIDEOBUF_IDLE;??
  • ????????init_waitqueue_head(&myuvc_queue.buffer[i].wait);??
  • ????}??
  • ??
  • ????myuvc_queue.mem?=?mem;??
  • ????myuvc_queue.count?=?nbuffers;??
  • ????myuvc_queue.buf_size?=?bufsize;??
  • ????ret?=?nbuffers;??
  • ??
  • done:??
  • ????return?ret;??
  • }??
  • ??
  • /*?A8?查詢緩存狀態(tài),?比如地址信息(APP可以用mmap進(jìn)行映射)??
  • ?*?參考?uvc_query_buffer?
  • ?*/??
  • static?int?myuvc_vidioc_querybuf(struct?file?*file,?void?*priv,?struct?v4l2_buffer?*v4l2_buf)??
  • {??
  • ????int?ret?=?0;??
  • ??????
  • ????if?(v4l2_buf->index?>=?myuvc_queue.count)?{??
  • ????????ret?=?-EINVAL;??
  • ????????goto?done;??
  • ????}??
  • ??
  • ????memcpy(v4l2_buf,?&myuvc_queue.buffer[v4l2_buf->index].buf,?sizeof(*v4l2_buf));??
  • ??
  • ????/*?更新flags?*/??
  • ????if?(myuvc_queue.buffer[v4l2_buf->index].vma_use_count)??
  • ????????v4l2_buf->flags?|=?V4L2_BUF_FLAG_MAPPED;??
  • ??
  • ??
  • ????switch?(myuvc_queue.buffer[v4l2_buf->index].state)?{??
  • ????????case?VIDEOBUF_ERROR:??
  • ????????case?VIDEOBUF_DONE:??
  • ????????????v4l2_buf->flags?|=?V4L2_BUF_FLAG_DONE;??
  • ????????????break;??
  • ????????case?VIDEOBUF_QUEUED:??
  • ????????case?VIDEOBUF_ACTIVE:??
  • ????????????v4l2_buf->flags?|=?V4L2_BUF_FLAG_QUEUED;??
  • ????????????break;??
  • ????????case?VIDEOBUF_IDLE:??
  • ????????default:??
  • ????????????break;??
  • ????}??
  • ??
  • done:??????
  • ????return?ret;??
  • }??
  • ??
  • /*?A10?把緩沖區(qū)放入隊(duì)列,?底層的硬件操作函數(shù)將會把數(shù)據(jù)放入這個(gè)隊(duì)列的緩存??
  • ?*?參考:?uvc_queue_buffer?
  • ?*/??
  • static?int?myuvc_vidioc_qbuf(struct?file?*file,?void?*priv,?struct?v4l2_buffer?*v4l2_buf)??
  • {??
  • ????struct?myuvc_buffer?*buf;??
  • ??
  • ????/*?0.?APP傳入的v4l2_buf可能有問題,?要做判斷?*/??
  • ??
  • ????if?(v4l2_buf->type?!=?V4L2_BUF_TYPE_VIDEO_CAPTURE?||??
  • ????????v4l2_buf->memory?!=?V4L2_MEMORY_MMAP)?{??
  • ????????return?-EINVAL;??
  • ????}??
  • ??
  • ????if?(v4l2_buf->index?>=?myuvc_queue.count)?{??
  • ????????return?-EINVAL;??
  • ????}??
  • ??
  • ????buf?=?&myuvc_queue.buffer[v4l2_buf->index];??
  • ??
  • ????if?(buf->state?!=?VIDEOBUF_IDLE)?{??
  • ????????return?-EINVAL;??
  • ????}??
  • ??
  • ??
  • ????/*?1.?修改狀態(tài)?*/??
  • ????buf->state?=?VIDEOBUF_QUEUED;??
  • ????buf->buf.bytesused?=?0;??
  • ??
  • ????/*?2.?放入2個(gè)隊(duì)列?*/??
  • ????/*?隊(duì)列1:?供APP使用??
  • ?????*?當(dāng)緩沖區(qū)沒有數(shù)據(jù)時(shí),放入mainqueue隊(duì)列?
  • ?????*?當(dāng)緩沖區(qū)有數(shù)據(jù)時(shí),?APP從mainqueue隊(duì)列中取出?
  • ?????*/??
  • ????list_add_tail(&buf->stream,?&myuvc_queue.mainqueue);??
  • ??
  • ????/*?隊(duì)列2:?供產(chǎn)生數(shù)據(jù)的函數(shù)使用?
  • ?????*?當(dāng)采集到數(shù)據(jù)時(shí),從irqqueue隊(duì)列中取出第1個(gè)緩沖區(qū),存入數(shù)據(jù)?
  • ?????*/??
  • ????list_add_tail(&buf->irq,?&myuvc_queue.irqqueue);??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • static?void?myuvc_print_streaming_params(struct?myuvc_streaming_control?*ctrl)??
  • {??
  • ????printk("video?params:\n");??
  • ????printk("bmHint???????????????????=?%d\n",?ctrl->bmHint);??
  • ????printk("bFormatIndex?????????????=?%d\n",?ctrl->bFormatIndex);??
  • ????printk("bFrameIndex??????????????=?%d\n",?ctrl->bFrameIndex);??
  • ????printk("dwFrameInterval??????????=?%d\n",?ctrl->dwFrameInterval);??
  • ????printk("wKeyFrameRate????????????=?%d\n",?ctrl->wKeyFrameRate);??
  • ????printk("wPFrameRate??????????????=?%d\n",?ctrl->wPFrameRate);??
  • ????printk("wCompQuality?????????????=?%d\n",?ctrl->wCompQuality);??
  • ????printk("wCompWindowSize??????????=?%d\n",?ctrl->wCompWindowSize);??
  • ????printk("wDelay???????????????????=?%d\n",?ctrl->wDelay);??
  • ????printk("dwMaxVideoFrameSize??????=?%d\n",?ctrl->dwMaxVideoFrameSize);??
  • ????printk("dwMaxPayloadTransferSize?=?%d\n",?ctrl->dwMaxPayloadTransferSize);??
  • ????printk("dwClockFrequency?????????=?%d\n",?ctrl->dwClockFrequency);??
  • ????printk("bmFramingInfo????????????=?%d\n",?ctrl->bmFramingInfo);??
  • ????printk("bPreferedVersion?????????=?%d\n",?ctrl->bPreferedVersion);??
  • ????printk("bMinVersion??????????????=?%d\n",?ctrl->bMinVersion);??
  • ????printk("bMinVersion??????????????=?%d\n",?ctrl->bMinVersion);??
  • }??
  • ??
  • ??
  • /*?參考:?uvc_get_video_ctrl??
  • ?(ret?=?uvc_get_video_ctrl(video,?probe,?1,?GET_CUR))??
  • ?static?int?uvc_get_video_ctrl(struct?uvc_video_device?*video,?
  • ?????struct?uvc_streaming_control?*ctrl,?int?probe,?__u8?query)?
  • ?*/??
  • static?int?myuvc_get_streaming_params(struct?myuvc_streaming_control?*ctrl)??
  • {??
  • ????__u8?*data;??
  • ????__u16?size;??
  • ????int?ret;??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ??
  • ????size?=?uvc_version?>=?0x0110???34?:?26;??
  • ????data?=?kmalloc(size,?GFP_KERNEL);??
  • ????if?(data?==?NULL)??
  • ????????return?-ENOMEM;??
  • ?????
  • ????pipe?=?(GET_CUR?&?0x80)???usb_rcvctrlpipe(myuvc_udev,?0)??
  • ??????????????????:?usb_sndctrlpipe(myuvc_udev,?0);??
  • ????type?|=?(GET_CUR?&?0x80)???USB_DIR_IN?:?USB_DIR_OUT;??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_CUR,?type,?VS_PROBE_CONTROL?<<?8,??
  • ????????????0?<<?8?|?myuvc_streaming_intf,?data,?size,?5000);??
  • ??
  • ????if?(ret?<?0)??
  • ????????goto?done;??
  • ??
  • ????ctrl->bmHint?=?le16_to_cpup((__le16?*)&data[0]);??
  • ????ctrl->bFormatIndex?=?data[2];??
  • ????ctrl->bFrameIndex?=?data[3];??
  • ????ctrl->dwFrameInterval?=?le32_to_cpup((__le32?*)&data[4]);??
  • ????ctrl->wKeyFrameRate?=?le16_to_cpup((__le16?*)&data[8]);??
  • ????ctrl->wPFrameRate?=?le16_to_cpup((__le16?*)&data[10]);??
  • ????ctrl->wCompQuality?=?le16_to_cpup((__le16?*)&data[12]);??
  • ????ctrl->wCompWindowSize?=?le16_to_cpup((__le16?*)&data[14]);??
  • ????ctrl->wDelay?=?le16_to_cpup((__le16?*)&data[16]);??
  • ????ctrl->dwMaxVideoFrameSize?=?get_unaligned_le32(&data[18]);??
  • ????ctrl->dwMaxPayloadTransferSize?=?get_unaligned_le32(&data[22]);??
  • ??
  • ????if?(size?==?34)?{??
  • ????????ctrl->dwClockFrequency?=?get_unaligned_le32(&data[26]);??
  • ????????ctrl->bmFramingInfo?=?data[30];??
  • ????????ctrl->bPreferedVersion?=?data[31];??
  • ????????ctrl->bMinVersion?=?data[32];??
  • ????????ctrl->bMaxVersion?=?data[33];??
  • ????}?else?{??
  • ????????//ctrl->dwClockFrequency?=?video->dev->clock_frequency;??
  • ????????ctrl->bmFramingInfo?=?0;??
  • ????????ctrl->bPreferedVersion?=?0;??
  • ????????ctrl->bMinVersion?=?0;??
  • ????????ctrl->bMaxVersion?=?0;??
  • ????}??
  • ??
  • done:??
  • ????kfree(data);??
  • ??????
  • ????return?(ret?<?0)???ret?:?0;??
  • }??
  • ??
  • /*?參考:?uvc_v4l2_try_format?∕uvc_probe_video??
  • ?*???????uvc_set_video_ctrl(video,?probe,?1)?
  • ?*/??
  • static?int?myuvc_try_streaming_params(struct?myuvc_streaming_control?*ctrl)??
  • {??
  • ????__u8?*data;??
  • ????__u16?size;??
  • ????int?ret;??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ??????
  • ????memset(ctrl,?0,?sizeof?*ctrl);??
  • ??????
  • ????ctrl->bmHint?=?1;????/*?dwFrameInterval?*/??
  • ????ctrl->bFormatIndex?=?1;??
  • ????ctrl->bFrameIndex??=?frame_idx?+?1;??
  • ????ctrl->dwFrameInterval?=?333333;??
  • ??
  • ??
  • ????size?=?uvc_version?>=?0x0110???34?:?26;??
  • ????data?=?kzalloc(size,?GFP_KERNEL);??
  • ????if?(data?==?NULL)??
  • ????????return?-ENOMEM;??
  • ??
  • ????*(__le16?*)&data[0]?=?cpu_to_le16(ctrl->bmHint);??
  • ????data[2]?=?ctrl->bFormatIndex;??
  • ????data[3]?=?ctrl->bFrameIndex;??
  • ????*(__le32?*)&data[4]?=?cpu_to_le32(ctrl->dwFrameInterval);??
  • ????*(__le16?*)&data[8]?=?cpu_to_le16(ctrl->wKeyFrameRate);??
  • ????*(__le16?*)&data[10]?=?cpu_to_le16(ctrl->wPFrameRate);??
  • ????*(__le16?*)&data[12]?=?cpu_to_le16(ctrl->wCompQuality);??
  • ????*(__le16?*)&data[14]?=?cpu_to_le16(ctrl->wCompWindowSize);??
  • ????*(__le16?*)&data[16]?=?cpu_to_le16(ctrl->wDelay);??
  • ????put_unaligned_le32(ctrl->dwMaxVideoFrameSize,?&data[18]);??
  • ????put_unaligned_le32(ctrl->dwMaxPayloadTransferSize,?&data[22]);??
  • ??
  • ????if?(size?==?34)?{??
  • ????????put_unaligned_le32(ctrl->dwClockFrequency,?&data[26]);??
  • ????????data[30]?=?ctrl->bmFramingInfo;??
  • ????????data[31]?=?ctrl->bPreferedVersion;??
  • ????????data[32]?=?ctrl->bMinVersion;??
  • ????????data[33]?=?ctrl->bMaxVersion;??
  • ????}??
  • ??
  • ????pipe?=?(SET_CUR?&?0x80)???usb_rcvctrlpipe(myuvc_udev,?0)??
  • ??????????????????:?usb_sndctrlpipe(myuvc_udev,?0);??
  • ????type?|=?(SET_CUR?&?0x80)???USB_DIR_IN?:?USB_DIR_OUT;??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?SET_CUR,?type,?VS_PROBE_CONTROL?<<?8,??
  • ????????????0?<<?8?|?myuvc_streaming_intf,?data,?size,?5000);??
  • ??
  • ????kfree(data);??
  • ??????
  • ????return?(ret?<?0)???ret?:?0;??
  • ??????
  • }??
  • ??
  • ??
  • /*?參考:?uvc_v4l2_try_format?∕uvc_probe_video??
  • ?*???????uvc_set_video_ctrl(video,?probe,?1)?
  • ?*/??
  • static?int?myuvc_set_streaming_params(struct?myuvc_streaming_control?*ctrl)??
  • {??
  • ????__u8?*data;??
  • ????__u16?size;??
  • ????int?ret;??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ??????
  • ????size?=?uvc_version?>=?0x0110???34?:?26;??
  • ????data?=?kzalloc(size,?GFP_KERNEL);??
  • ????if?(data?==?NULL)??
  • ????????return?-ENOMEM;??
  • ??
  • ????*(__le16?*)&data[0]?=?cpu_to_le16(ctrl->bmHint);??
  • ????data[2]?=?ctrl->bFormatIndex;??
  • ????data[3]?=?ctrl->bFrameIndex;??
  • ????*(__le32?*)&data[4]?=?cpu_to_le32(ctrl->dwFrameInterval);??
  • ????*(__le16?*)&data[8]?=?cpu_to_le16(ctrl->wKeyFrameRate);??
  • ????*(__le16?*)&data[10]?=?cpu_to_le16(ctrl->wPFrameRate);??
  • ????*(__le16?*)&data[12]?=?cpu_to_le16(ctrl->wCompQuality);??
  • ????*(__le16?*)&data[14]?=?cpu_to_le16(ctrl->wCompWindowSize);??
  • ????*(__le16?*)&data[16]?=?cpu_to_le16(ctrl->wDelay);??
  • ????put_unaligned_le32(ctrl->dwMaxVideoFrameSize,?&data[18]);??
  • ????put_unaligned_le32(ctrl->dwMaxPayloadTransferSize,?&data[22]);??
  • ??
  • ????if?(size?==?34)?{??
  • ????????put_unaligned_le32(ctrl->dwClockFrequency,?&data[26]);??
  • ????????data[30]?=?ctrl->bmFramingInfo;??
  • ????????data[31]?=?ctrl->bPreferedVersion;??
  • ????????data[32]?=?ctrl->bMinVersion;??
  • ????????data[33]?=?ctrl->bMaxVersion;??
  • ????}??
  • ??
  • ????pipe?=?(SET_CUR?&?0x80)???usb_rcvctrlpipe(myuvc_udev,?0)??
  • ??????????????????:?usb_sndctrlpipe(myuvc_udev,?0);??
  • ????type?|=?(SET_CUR?&?0x80)???USB_DIR_IN?:?USB_DIR_OUT;??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?SET_CUR,?type,?VS_COMMIT_CONTROL?<<?8,??
  • ????????????0?<<?8?|?myuvc_streaming_intf,?data,?size,?5000);??
  • ??
  • ????kfree(data);??
  • ??????
  • ????return?(ret?<?0)???ret?:?0;??
  • ??????
  • }??
  • ??
  • static?void?myuvc_uninit_urbs(void)??
  • {??
  • ????int?i;??
  • ????for?(i?=?0;?i?<?MYUVC_URBS;?++i)?{??
  • ????????if?(myuvc_queue.urb_buffer[i])??
  • ????????{??
  • ????????????usb_buffer_free(myuvc_udev,?myuvc_queue.urb_size,?myuvc_queue.urb_buffer[i],?myuvc_queue.urb_dma[i]);??
  • ????????????myuvc_queue.urb_buffer[i]?=?NULL;??
  • ????????}??
  • ??
  • ????????if?(myuvc_queue.urb[i])??
  • ????????{??
  • ????????????usb_free_urb(myuvc_queue.urb[i]);??
  • ????????????myuvc_queue.urb[i]?=?NULL;??
  • ????????}??
  • ????}??
  • }??
  • ??
  • /*?參考:?uvc_video_complete?/?uvc_video_decode_isoc?*/??
  • static?void?myuvc_video_complete(struct?urb?*urb)??
  • {??
  • ????u8?*src;??
  • ????u8?*dest;??
  • ????int?ret,?i;??
  • ????int?len;??
  • ????int?maxlen;??
  • ????int?nbytes;??
  • ????struct?myuvc_buffer?*buf;??
  • ????static?int?fid;??
  • ????static?int?wake_cnt?=?0;??
  • ??
  • ????//?要修改影像資料,必須先宣告一個(gè)特別型態(tài)的指標(biāo)變數(shù),才能正確存取記憶體中的資料??
  • ????unsigned?char?*point_mem;??
  • ????static?unsigned?char?*mem_temp?=?NULL;??
  • ??
  • ????//?初始化暫存用的記憶體位置??
  • ????static?unsigned?int?nArrayTemp_Size?=?1000;??
  • ??
  • ????u8*?mem;??
  • ????int?data_len;??
  • ??????
  • ????switch?(urb->status)?{??
  • ????case?0:??
  • ????????break;??
  • ??
  • ????default:??
  • ????????printk("Non-zero?status?(%d)?in?video?"??
  • ????????????"completion?handler.\n",?urb->status);??
  • ????????return;??
  • ????}??
  • ??
  • ????/*?如果irqqueue隊(duì)列不空的話,從irqqueue隊(duì)列中取出第1個(gè)緩沖區(qū),用于存放urb的數(shù)據(jù)?*/??
  • ????if?(!list_empty(&myuvc_queue.irqqueue))??
  • ????{??
  • ????????buf?=?list_first_entry(&myuvc_queue.irqqueue,?struct?myuvc_buffer,?irq);??
  • ????}??
  • ????else??
  • ????{??
  • ????????/*?什么情況下會導(dǎo)致irqqueue隊(duì)列為空呢??
  • ?????????*?usb設(shè)備填充數(shù)據(jù)太快,但是應(yīng)用程序沒能及時(shí)處理?
  • ?????????*/??
  • ????????buf?=?NULL;??
  • ????}??
  • ??????
  • ????/*?開始處理urb中的每一個(gè)小包?*/??
  • ????for?(i?=?0;?i?<?urb->number_of_packets;?++i)?{??
  • ????????if?(urb->iso_frame_desc[i].status?<?0)?{??
  • ????????????//printk("USB?isochronous?frame?"??
  • ????????????//??"lost?(%d).\n",?urb->iso_frame_desc[i].status);??
  • ????????????continue;??
  • ????????}??
  • ??
  • ????????src??=?urb->transfer_buffer?+?urb->iso_frame_desc[i].offset;??
  • ??
  • ??
  • ????????len?=?urb->iso_frame_desc[i].actual_length;??
  • ????????/*?判斷數(shù)據(jù)是否有效?*/??
  • ????????/*?URB數(shù)據(jù)含義:?
  • ?????????*?data[0]?:?頭部長度?
  • ?????????*?data[1]?:?錯(cuò)誤狀態(tài)?
  • ?????????*/??
  • ????????if?(len?<?2?||?src[0]?<?2?||?src[0]?>?len)??
  • ????????????continue;??
  • ??????????
  • ????????/*?Skip?payloads?marked?with?the?error?bit?("error?frames").?*/??
  • ????????if?(src[1]?&?UVC_STREAM_ERR)?{??
  • ????????????//printk("Dropping?payload?(error?bit?set).\n");??
  • ????????????continue;??
  • ????????}??
  • ??
  • ????????/*?根據(jù)ip2970/ip2977廠家提供的修改手冊,如果想要支持ip2970/ip2977就必須?
  • ?????????*?添加如下代碼??
  • ?????????*/??
  • ????????if?(myuvc_udev->descriptor.idVendor?==?0x1B3B)??
  • ????????{??
  • ????????????if?(?len?>=?16?)?//?have?data?in?buffer??
  • ????????????{??
  • ????????????????//?資料必須從data[12]開始判斷,是因?yàn)榍懊娴馁Y料是封包專用??
  • ????????????????if?(?(src[12]==0xFF?&&?src[13]==0xD8?&&?src[14]==0xFF)?||??
  • ????????????????????(src[12]==0xD8?&&?src[13]==0xFF?&&?src[14]==0xC4))???
  • ????????????????{??
  • ????????????????????if(last_fid)??
  • ????????????????????????fid?&=?~UVC_STREAM_FID;??
  • ????????????????????else??
  • ????????????????????????fid?|=?UVC_STREAM_FID;??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????else??
  • ????????{??
  • ????????????fid?=?src[1]?&?UVC_STREAM_FID;??
  • ????????}??
  • ??
  • ????????/*?Store?the?payload?FID?bit?and?return?immediately?when?the?buffer?is?
  • ?????????*?NULL.?
  • ?????????*/??
  • ????????if?(buf?==?NULL)?{??
  • ????????????last_fid?=?fid;??
  • ????????????continue;??
  • ????????}??
  • ??
  • ????????/*?根據(jù)FID判斷當(dāng)前幀的數(shù)據(jù)是否結(jié)束?*/??
  • ????????/*?VIDEOBUF_ACTIVE表示正在接收數(shù)據(jù),buf->state!=?VIDEOBUF_ACTIVE,?表示"之前還未接收數(shù)據(jù)",??
  • ?????????*?因此就是說即將接收數(shù)據(jù)?
  • ????????*/????
  • ????????if?(buf->state?!=?VIDEOBUF_ACTIVE)?{???????????
  • ????????????if?(fid?==?last_fid)?{??
  • ????????????????/*?既然你剛開始接收數(shù)據(jù),?那么FID應(yīng)該是一個(gè)新的值,不應(yīng)該等于原來的last_fid?*/??
  • ????????????????continue;??
  • ????????????}??
  • ??
  • ????????????/*?表示開始接收第1個(gè)數(shù)據(jù)?*/??
  • ????????????buf->state?=?VIDEOBUF_ACTIVE;??
  • ????????}??
  • ??
  • ????????/*?fid表示當(dāng)前的fid。?
  • ?????????*?fid?!=?last_fid?表示開始新一幀了,當(dāng)前的buffer已經(jīng)被填充完了。?
  • ?????????*?這個(gè)地方是從fid來判斷是否一幀數(shù)據(jù)已經(jīng)結(jié)束,下面還有從數(shù)據(jù)是否填充不下了來?
  • ?????????*?強(qiáng)制認(rèn)為一幀數(shù)據(jù)已經(jīng)結(jié)束?
  • ?????????*/??
  • ????????if?(fid?!=?last_fid?&&?buf->buf.bytesused?!=?0)?{??
  • ????????????buf->state?=?VIDEOBUF_DONE;??
  • ??
  • ????????????/*?從隊(duì)列中刪除,?喚醒進(jìn)程?*/??
  • ????????????list_del(&buf->irq);??
  • ????????????wake_up(&buf->wait);??
  • ??
  • ????????????mem?=?myuvc_queue.mem?+?buf->buf.m.offset;??
  • ????????????data_len?=?buf->buf.bytesused;??
  • ????????????//printk("wake_up?%d?:?%s?%d,?start?data:?%02x?%02x,?end?data:?%02x?%02x",?wake_cnt++,?__FUNCTION__,?__LINE__,?mem[0],?mem[1],?mem[data_len?-?2],?mem[data_len?-?1]);??
  • ??
  • ????????????/*?取出下一個(gè)buf?*/??
  • ????????????if?(!list_empty(&myuvc_queue.irqqueue))??
  • ????????????{??
  • ????????????????buf?=?list_first_entry(&myuvc_queue.irqqueue,?struct?myuvc_buffer,?irq);??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????buf?=?NULL;??
  • ????????????}??
  • ????????????continue;??
  • ????????}??
  • ????????last_fid?=?fid;??
  • ??
  • ????????dest?=?myuvc_queue.mem?+?buf->buf.m.offset?+?buf->buf.bytesused;??
  • ??
  • ????????/*?除去頭部后的數(shù)據(jù)長度?*/??
  • ????????len?-=?src[0];??
  • ??
  • ????????/*?緩沖區(qū)最多還能存多少數(shù)據(jù)?*/??
  • ????????maxlen?=?buf->buf.length?-?buf->buf.bytesused;??
  • ????????nbytes?=?min(len,?maxlen);??
  • ??
  • ????????/*?復(fù)制數(shù)據(jù)?*/??
  • ????????memcpy(dest,?src?+?src[0],?nbytes);??
  • ????????buf->buf.bytesused?+=?nbytes;??
  • ??
  • ????????/*?ip2970/ip2977?*/??
  • ????????if?(myuvc_udev->descriptor.idVendor?==?0x1B3B)??
  • ????????{??
  • ????????????if(mem_temp?==?NULL)?{??
  • ????????????????mem_temp?=?kmalloc(nArrayTemp_Size,?GFP_KERNEL);??
  • ????????????}??
  • ????????????else?if(nArrayTemp_Size?<=?nbytes){?//?當(dāng)收到的資料長度大於上一次的資料長度,則重新分配所需的空間+??
  • ????????????????kfree(mem_temp);??
  • ????????????????nArrayTemp_Size?+=?500;??
  • ????????????????mem_temp?=?kmalloc(nArrayTemp_Size,?GFP_KERNEL);??
  • ????????????}??
  • ????????????memset(mem_temp,?0x00,?nArrayTemp_Size);??
  • ??????????????
  • ????????????//?指向資料儲存的記憶體位置??
  • ????????????point_mem?=?(unsigned?char?*)dest;??
  • ????????????if(?*(point_mem)?==?0xD8?&&?*(point_mem?+?1)?==?0xFF?&&?*(point_mem?+?2)?==?0xC4){??
  • ????????????????memcpy(?mem_temp?+?1,?point_mem,?nbytes);??
  • ????????????????mem_temp[0]?=?0xFF;??
  • ????????????????memcpy(point_mem,?mem_temp,?nbytes?+?1);??
  • ????????????}??
  • ????????}??
  • ??
  • ??
  • ??
  • ????????/*?判斷一幀數(shù)據(jù)是否已經(jīng)全部接收到??
  • ?????????*?如果數(shù)據(jù)已經(jīng)滿了,就強(qiáng)制認(rèn)為已經(jīng)結(jié)束了?
  • ?????????*/??
  • ????????if?(len?>?maxlen)?{??
  • ????????????buf->state?=?VIDEOBUF_DONE;??
  • ????????}??
  • ??????????
  • ????????/*?Mark?the?buffer?as?done?if?the?EOF?marker?is?set.?*/??
  • ????????if?(src[1]?&?UVC_STREAM_EOF?&&?buf->buf.bytesused?!=?0)?{??
  • ???????????//?printk("Frame?complete?(EOF?found).\n");??
  • ????????????//if?(len?==?0)??
  • ???????????//?????printk("EOF?in?empty?payload.\n");??
  • ????????????buf->state?=?VIDEOBUF_DONE;??
  • ????????}??
  • ??
  • ????????/*?當(dāng)接收完一幀數(shù)據(jù),??
  • ?????????*?從irqqueue中刪除這個(gè)緩沖區(qū)?
  • ?????????*?喚醒等待數(shù)據(jù)的進(jìn)程??
  • ?????????*/??
  • ????????if?(buf->state?==?VIDEOBUF_DONE?||??
  • ????????????buf->state?==?VIDEOBUF_ERROR)??
  • ????????{??
  • ????????????list_del(&buf->irq);??
  • ????????????wake_up(&buf->wait);??
  • ??
  • ????????????mem?=?myuvc_queue.mem?+?buf->buf.m.offset;??
  • ????????????data_len?=?buf->buf.bytesused;??
  • ????????????//printk("wake_up?%d?:?%s?%d,?start?data:?%02x?%02x,?end?data:?%02x?%02x",?wake_cnt++,?__FUNCTION__,?__LINE__,?mem[0],?mem[1],?mem[data_len?-?2],?mem[data_len?-?1]);??
  • ??????????????
  • ????????????/*?取出下一個(gè)buf?*/??
  • ????????????if?(!list_empty(&myuvc_queue.irqqueue))??
  • ????????????{??
  • ????????????????buf?=?list_first_entry(&myuvc_queue.irqqueue,?struct?myuvc_buffer,?irq);??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????buf?=?NULL;??
  • ????????????}??
  • ????????}??
  • ??
  • ????}??
  • ??
  • ??
  • ????/*?再次提交URB?*/??
  • ????if?((ret?=?usb_submit_urb(urb,?GFP_ATOMIC))?<?0)?{??
  • ????????printk("Failed?to?resubmit?video?URB?(%d).\n",?ret);??
  • ????}??
  • }??
  • ??
  • /*?參考:?uvc_init_video_isoc?*/??
  • static?int?myuvc_alloc_init_urbs(void)??
  • {??
  • ????u16?psize;??
  • ????u32?size;??
  • ????int?npackets;??
  • ????int?i;??
  • ????int?j;??
  • ??
  • ????struct?urb?*urb;??
  • ??
  • ????psize?=?wMaxPacketSize;?/*?實(shí)時(shí)傳輸端點(diǎn)一次能傳輸?shù)淖畲笞止?jié)數(shù)?*/??
  • ????size??=?myuvc_params.dwMaxVideoFrameSize;??/*?一幀數(shù)據(jù)的最大長度?*/??
  • ????npackets?=?DIV_ROUND_UP(size,?psize);??
  • ????if?(npackets?>?32)??
  • ????????npackets?=?32;??
  • ??
  • ????size?=?myuvc_queue.urb_size?=?psize?*?npackets;??
  • ??????
  • ????for?(i?=?0;?i?<?MYUVC_URBS;?++i)?{??
  • ????????/*?1.?分配usb_buffers?*/??
  • ??????????
  • ????????myuvc_queue.urb_buffer[i]?=?usb_buffer_alloc(??
  • ????????????myuvc_udev,?size,??
  • ????????????GFP_KERNEL?|?__GFP_NOWARN,?&myuvc_queue.urb_dma[i]);??
  • ??
  • ????????/*?2.?分配urb?*/??
  • ????????myuvc_queue.urb[i]?=?usb_alloc_urb(npackets,?GFP_KERNEL);??
  • ??
  • ????????if?(!myuvc_queue.urb_buffer[i]?||?!myuvc_queue.urb[i])??
  • ????????{??
  • ????????????myuvc_uninit_urbs();??
  • ????????????return?-ENOMEM;??
  • ????????}??
  • ??
  • ????}??
  • ??
  • ??
  • ????/*?3.?設(shè)置urb?*/??
  • ????for?(i?=?0;?i?<?MYUVC_URBS;?++i)?{??
  • ????????urb?=?myuvc_queue.urb[i];??
  • ??????????
  • ????????urb->dev?=?myuvc_udev;??
  • ????????urb->context?=?NULL;??
  • ????????urb->pipe?=?usb_rcvisocpipe(myuvc_udev,myuvc_bEndpointAddress);??
  • ????????urb->transfer_flags?=?URB_ISO_ASAP?|?URB_NO_TRANSFER_DMA_MAP;??
  • ????????urb->interval?=?1;??
  • ????????urb->transfer_buffer?=?myuvc_queue.urb_buffer[i];??
  • ????????urb->transfer_dma?=?myuvc_queue.urb_dma[i];??
  • ????????urb->complete?=?myuvc_video_complete;??
  • ????????urb->number_of_packets?=?npackets;??
  • ????????urb->transfer_buffer_length?=?size;??
  • ??????????
  • ????????for?(j?=?0;?j?<?npackets;?++j)?{??
  • ????????????urb->iso_frame_desc[j].offset?=?j?*?psize;??
  • ????????????urb->iso_frame_desc[j].length?=?psize;??
  • ????????}??
  • ??????
  • ????}??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?A11?啟動(dòng)傳輸??
  • ?*?參考:?uvc_video_enable(video,?1):?
  • ?*???????????uvc_commit_video?
  • ?*???????????uvc_init_video?
  • ?*/??
  • static?int?myuvc_vidioc_streamon(struct?file?*file,?void?*priv,?enum?v4l2_buf_type?i)??
  • {??
  • ????int?ret;??
  • ??????
  • ????/*?1.?向USB攝像頭設(shè)置參數(shù):?比如使用哪個(gè)format,?使用這個(gè)format下的哪個(gè)frame(分辨率)??
  • ?????*?參考:?uvc_set_video_ctrl?/?uvc_get_video_ctrl?
  • ?????*?1.1?根據(jù)一個(gè)結(jié)構(gòu)體uvc_streaming_control設(shè)置數(shù)據(jù)包:?可以手工設(shè)置,也可以讀出后再修改?
  • ?????*?1.2?調(diào)用usb_control_msg發(fā)出數(shù)據(jù)包?
  • ?????*/??
  • ??
  • ????/*?a.?測試參數(shù)?*/??
  • ????ret?=?myuvc_try_streaming_params(&myuvc_params);??
  • ????printk("myuvc_try_streaming_params?ret?=?%d\n",?ret);??
  • ??
  • ????/*?b.?取出參數(shù)?*/??
  • ????ret?=?myuvc_get_streaming_params(&myuvc_params);??
  • ????printk("myuvc_get_streaming_params?ret?=?%d\n",?ret);??
  • ??
  • ????/*?c.?設(shè)置參數(shù)?*/??
  • ????ret?=?myuvc_set_streaming_params(&myuvc_params);??
  • ????printk("myuvc_set_streaming_params?ret?=?%d\n",?ret);??
  • ??????
  • ????myuvc_print_streaming_params(&myuvc_params);??
  • ??
  • ????/*?d.?設(shè)置VideoStreaming?Interface所使用的setting?
  • ?????*?d.1?從myuvc_params確定帶寬?
  • ?????*?d.2?根據(jù)setting的endpoint能傳輸?shù)膚MaxPacketSize?
  • ?????*?????找到能滿足該帶寬的setting?
  • ?????*/??
  • ????/*?手工確定:?
  • ?????*?bandwidth?=?myuvc_params.dwMaxPayloadTransferSize?=?800?
  • ?????*?觀察lsusb?-v?-d?0x1e4e:的結(jié)果:?
  • ?????*????????????????wMaxPacketSize?????0x0320??1x?800?bytes?
  • ?????*?bAlternateSetting???????5?
  • ?????*/??
  • ????usb_set_interface(myuvc_udev,?myuvc_streaming_intf,?myuvc_streaming_bAlternateSetting);??
  • ??????
  • ????/*?2.?分配設(shè)置URB?*/??
  • ????ret?=?myuvc_alloc_init_urbs();??
  • ????if?(ret)??
  • ????????printk("myuvc_alloc_init_urbs?err?:?ret?=?%d\n",?ret);??
  • ??
  • ????/*?3.?提交URB以接收數(shù)據(jù)?*/??
  • ????for?(i?=?0;?i?<?MYUVC_URBS;?++i)?{??
  • ????????if?((ret?=?usb_submit_urb(myuvc_queue.urb[i],?GFP_KERNEL))?<?0)?{??
  • ????????????printk("Failed?to?submit?URB?%u?(%d).\n",?i,?ret);??
  • ????????????myuvc_uninit_urbs();??
  • ????????????return?ret;??
  • ????????}??
  • ????}??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?A13?APP通過poll/select確定有數(shù)據(jù)后,?把緩存從隊(duì)列中取出來?
  • ?*?參考:?uvc_dequeue_buffer?
  • ?*/??
  • static?int?myuvc_vidioc_dqbuf(struct?file?*file,?void?*priv,?struct?v4l2_buffer?*v4l2_buf)??
  • {??
  • ????/*?APP發(fā)現(xiàn)數(shù)據(jù)就緒后,?從mainqueue里取出這個(gè)buffer?*/??
  • ??
  • ????struct?myuvc_buffer?*buf;??
  • ????int?ret?=?0;??
  • ??
  • ????if?(list_empty(&myuvc_queue.mainqueue))?{??
  • ????????ret?=?-EINVAL;??
  • ????????goto?done;??
  • ????}??
  • ??????
  • ????buf?=?list_first_entry(&myuvc_queue.mainqueue,?struct?myuvc_buffer,?stream);??
  • ??
  • ????switch?(buf->state)?{??
  • ????case?VIDEOBUF_ERROR:??
  • ????????ret?=?-EIO;??
  • ????case?VIDEOBUF_DONE:??
  • ????????buf->state?=?VIDEOBUF_IDLE;??
  • ????????break;??
  • ??
  • ????case?VIDEOBUF_IDLE:??
  • ????case?VIDEOBUF_QUEUED:??
  • ????case?VIDEOBUF_ACTIVE:??
  • ????default:??
  • ????????ret?=?-EINVAL;??
  • ????????goto?done;??
  • ????}??
  • ??
  • ????list_del(&buf->stream);??
  • ????memcpy(v4l2_buf,?&buf->buf,?sizeof?*v4l2_buf);??
  • ??????
  • done:??
  • ????return?ret;??
  • }??
  • ??
  • /*?
  • ?*?A14?之前已經(jīng)通過mmap映射了緩存,?APP可以直接讀數(shù)據(jù)?
  • ?*?A15?再次調(diào)用myuvc_vidioc_qbuf把緩存放入隊(duì)列?
  • ?*?A16?poll...?
  • ?*/??
  • ??
  • /*?A17?停止??
  • ?*?參考?:?uvc_video_enable(video,?0)?
  • ?*/??
  • static?int?myuvc_vidioc_streamoff(struct?file?*file,?void?*priv,?enum?v4l2_buf_type?t)??
  • {??
  • ????struct?urb?*urb;??
  • ????unsigned?int?i;??
  • ??
  • ????/*?1.?kill?URB?*/??
  • ????for?(i?=?0;?i?<?MYUVC_URBS;?++i)?{??
  • ????????if?((urb?=?myuvc_queue.urb[i])?==?NULL)??
  • ????????????continue;??
  • ????????usb_kill_urb(urb);??
  • ????}??
  • ??
  • ????/*?2.?free?URB?*/??
  • ????myuvc_uninit_urbs();??
  • ??
  • ????/*?3.?設(shè)置VideoStreaming?Interface為setting?0?*/??
  • ????usb_set_interface(myuvc_udev,?myuvc_streaming_intf,?0);??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • ????/*?Control?handling?*/??
  • ??
  • ??
  • /*?Extract?the?bit?string?specified?by?mapping->offset?and?mapping->size?
  • ?*?from?the?little-endian?data?stored?at?'data'?and?return?the?result?as?
  • ?*?a?signed?32bit?integer.?Sign?extension?will?be?performed?if?the?mapping?
  • ?*?references?a?signed?data?type.?
  • ?*/??
  • static?__s32?myuvc_get_le_value(const?__u8?*data)??
  • {??
  • ????int?bits?=?16;??
  • ????int?offset?=?0;??
  • ????__s32?value?=?0;??
  • ????__u8?mask;??
  • ??
  • ????data?+=?offset?/?8;??
  • ????offset?&=?7;??
  • ????mask?=?((1LL?<<?bits)?-?1)?<<?offset;??
  • ??
  • ????for?(;?bits?>?0;?data++)?{??
  • ????????__u8?byte?=?*data?&?mask;??
  • ????????value?|=?offset?>?0???(byte?>>?offset)?:?(byte?<<?(-offset));??
  • ????????bits?-=?8?-?(offset?>?0???offset?:?0);??
  • ????????offset?-=?8;??
  • ????????mask?=?(1?<<?bits)?-?1;??
  • ????}??
  • ??
  • ????/*?Sign-extend?the?value?if?needed.?*/??
  • ????value?|=?-(value?&?(1?<<?(16?-?1)));??
  • ??
  • ????return?value;??
  • }??
  • ??
  • /*?Set?the?bit?string?specified?by?mapping->offset?and?mapping->size?
  • ?*?in?the?little-endian?data?stored?at?'data'?to?the?value?'value'.?
  • ?*/??
  • static?void?myuvc_set_le_value(__s32?value,?__u8?*data)??
  • {??
  • ????int?bits?=?16;??
  • ????int?offset?=?0;??
  • ????__u8?mask;??
  • ??
  • ????data?+=?offset?/?8;??
  • ????offset?&=?7;??
  • ??
  • ????for?(;?bits?>?0;?data++)?{??
  • ????????mask?=?((1LL?<<?bits)?-?1)?<<?offset;??
  • ????????*data?=?(*data?&?~mask)?|?((value?<<?offset)?&?mask);??
  • ????????value?>>=?offset???offset?:?8;??
  • ????????bits?-=?8?-?offset;??
  • ????????offset?=?0;??
  • ????}??
  • }??
  • ??????
  • ??
  • ??
  • /*?參考:uvc_query_v4l2_ctrl?*/??????
  • int?myuvc_vidioc_queryctrl?(struct?file?*file,?void?*fh,??
  • ????????????????struct?v4l2_queryctrl?*ctrl)??
  • {??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ????int?ret;??
  • ????u8?data[2];??
  • ??
  • ????if?(ctrl->id?!=?V4L2_CID_BRIGHTNESS)??
  • ????????return?-EINVAL;??
  • ??????
  • ????memset(ctrl,?0,?sizeof?*ctrl);??
  • ????ctrl->id???=?V4L2_CID_BRIGHTNESS;??
  • ????ctrl->type?=?V4L2_CTRL_TYPE_INTEGER;??
  • ????strcpy(ctrl->name,?"MyUVC_BRIGHTNESS");??
  • ????ctrl->flags?=?0;??
  • ??
  • ????pipe?=?usb_rcvctrlpipe(myuvc_udev,?0);??
  • ????type?|=?USB_DIR_IN;??
  • ??
  • ????/*?發(fā)起USB傳輸確定這些值?*/??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_MIN,?type,?PU_BRIGHTNESS_CONTROL?<<?8,??
  • ????????????ProcessingUnitID?<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ????ctrl->minimum?=?myuvc_get_le_value(data);????/*?Note?signedness?*/??
  • ??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_MAX,?type,??PU_BRIGHTNESS_CONTROL?<<?8,??
  • ????????????ProcessingUnitID?<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ????ctrl->maximum?=?myuvc_get_le_value(data);????/*?Note?signedness?*/??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_RES,?type,?PU_BRIGHTNESS_CONTROL?<<?8,??
  • ?????????????ProcessingUnitID?<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ????ctrl->step?=?myuvc_get_le_value(data);???/*?Note?signedness?*/??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_DEF,?type,?PU_BRIGHTNESS_CONTROL?<<?8,??
  • ????????????ProcessingUnitID?<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ????ctrl->default_value?=?myuvc_get_le_value(data);??/*?Note?signedness?*/??
  • ??
  • ????printk("Brightness:?min?=%d,?max?=?%d,?step?=?%d,?default?=?%d\n",?ctrl->minimum,?ctrl->maximum,?ctrl->step,?ctrl->default_value);??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?參考?:?uvc_ctrl_get?*/??
  • int?myuvc_vidioc_g_ctrl?(struct?file?*file,?void?*fh,??
  • ????????????????struct?v4l2_control?*ctrl)??
  • {??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ????int?ret;??
  • ????u8?data[2];??
  • ??????
  • ????if?(ctrl->id?!=?V4L2_CID_BRIGHTNESS)??
  • ????????return?-EINVAL;??
  • ??
  • ????pipe?=?usb_rcvctrlpipe(myuvc_udev,?0);??
  • ????type?|=?USB_DIR_IN;??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?GET_CUR,?type,?PU_BRIGHTNESS_CONTROL?<<?8,??
  • ????????????ProcessingUnitID?<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ????ctrl->value?=?myuvc_get_le_value(data);??/*?Note?signedness?*/??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • /*?參考:?uvc_ctrl_set/uvc_ctrl_commit?*/??
  • int?myuvc_vidioc_s_ctrl?(struct?file?*file,?void?*fh,??
  • ????????????????struct?v4l2_control?*ctrl)??
  • {??
  • ????__u8?type?=?USB_TYPE_CLASS?|?USB_RECIP_INTERFACE;??
  • ????unsigned?int?pipe;??
  • ????int?ret;??
  • ????u8?data[2];??
  • ??????
  • ????if?(ctrl->id?!=?V4L2_CID_BRIGHTNESS)??
  • ????????return?-EINVAL;??
  • ??
  • ????myuvc_set_le_value(ctrl->value,?data);??
  • ??
  • ????pipe?=?usb_sndctrlpipe(myuvc_udev,?0);??
  • ????type?|=?USB_DIR_OUT;??
  • ??
  • ????ret?=?usb_control_msg(myuvc_udev,?pipe,?SET_CUR,?type,?PU_BRIGHTNESS_CONTROL?<<?8,??
  • ????????????ProcessingUnitID??<<?8?|?myuvc_control_intf,?data,?2,?5000);??
  • ????if?(ret?!=?2)??
  • ????????return?-EIO;??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • ??
  • ??
  • static?const?struct?v4l2_ioctl_ops?myuvc_ioctl_ops?=?{??
  • ????????//?表示它是一個(gè)攝像頭設(shè)備??
  • ????????.vidioc_querycap??????=?myuvc_vidioc_querycap,??
  • ??
  • ????????/*?用于列舉、獲得、測試、設(shè)置攝像頭的數(shù)據(jù)的格式?*/??
  • ????????.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,??
  • ??????????
  • ????????/*?緩沖區(qū)操作:?申請/查詢/放入隊(duì)列/取出隊(duì)列?*/??
  • ????????.vidioc_reqbufs???????=?myuvc_vidioc_reqbufs,??
  • ????????.vidioc_querybuf??????=?myuvc_vidioc_querybuf,??
  • ????????.vidioc_qbuf??????????=?myuvc_vidioc_qbuf,??
  • ????????.vidioc_dqbuf?????????=?myuvc_vidioc_dqbuf,??
  • ??
  • ????????/*?查詢/獲得/設(shè)置屬性?*/??
  • ????????.vidioc_queryctrl?????=?myuvc_vidioc_queryctrl,??
  • ????????.vidioc_g_ctrl????????=?myuvc_vidioc_g_ctrl,??
  • ????????.vidioc_s_ctrl????????=?myuvc_vidioc_s_ctrl,??
  • ??????????
  • ????????//?啟動(dòng)/停止??
  • ????????.vidioc_streamon??????=?myuvc_vidioc_streamon,??
  • ????????.vidioc_streamoff?????=?myuvc_vidioc_streamoff,?????
  • };??
  • ??
  • /*?A1?*/??
  • static?int?myuvc_open(struct?file?*file)??
  • {??
  • ????return?0;??
  • }??
  • ??
  • static?void?myuvc_vm_open(struct?vm_area_struct?*vma)??
  • {??
  • ????struct?myuvc_buffer?*buffer?=?vma->vm_private_data;??
  • ????buffer->vma_use_count++;??
  • }??
  • ??
  • static?void?myuvc_vm_close(struct?vm_area_struct?*vma)??
  • {??
  • ????struct?myuvc_buffer?*buffer?=?vma->vm_private_data;??
  • ????buffer->vma_use_count--;??
  • }??
  • ??
  • static?struct?vm_operations_struct?myuvc_vm_ops?=?{??
  • ????.open???????=?myuvc_vm_open,??
  • ????.close??????=?myuvc_vm_close,??
  • };??
  • ??
  • ??
  • /*?A9?把緩存映射到APP的空間,以后APP就可以直接操作這塊緩存??
  • ?*?參考:?uvc_v4l2_mmap?
  • ?*/??
  • static?int?myuvc_mmap(struct?file?*file,?struct?vm_area_struct?*vma)??
  • {??
  • ????struct?myuvc_buffer?*buffer;??
  • ????struct?page?*page;??
  • ????unsigned?long?addr,?start,?size;??
  • ????unsigned?int?i;??
  • ????int?ret?=?0;??
  • ??
  • ????start?=?vma->vm_start;??
  • ????size?=?vma->vm_end?-?vma->vm_start;??
  • ??
  • ????/*?應(yīng)用程序調(diào)用mmap函數(shù)時(shí),?會傳入offset參數(shù)?
  • ?????*?根據(jù)這個(gè)offset找出指定的緩沖區(qū)?
  • ?????*/??
  • ????for?(i?=?0;?i?<?myuvc_queue.count;?++i)?{??
  • ????????buffer?=?&myuvc_queue.buffer[i];??
  • ????????if?((buffer->buf.m.offset?>>?PAGE_SHIFT)?==?vma->vm_pgoff)??
  • ????????????break;??
  • ????}??
  • ??
  • ????if?(i?==?myuvc_queue.count?||?size?!=?myuvc_queue.buf_size)?{??
  • ????????ret?=?-EINVAL;??
  • ????????goto?done;??
  • ????}??
  • ??
  • ????/*?
  • ?????*?VM_IO?marks?the?area?as?being?an?mmaped?region?for?I/O?to?a?
  • ?????*?device.?It?also?prevents?the?region?from?being?core?dumped.?
  • ?????*/??
  • ????vma->vm_flags?|=?VM_IO;??
  • ??
  • ????/*?根據(jù)虛擬地址找到緩沖區(qū)對應(yīng)的page構(gòu)體?*/??
  • ????addr?=?(unsigned?long)myuvc_queue.mem?+?buffer->buf.m.offset;??
  • ????while?(size?>?0)?{??
  • ????????page?=?vmalloc_to_page((void?*)addr);??
  • ??
  • ????????/*?把page和APP傳入的虛擬地址掛構(gòu)?*/??
  • ????????if?((ret?=?vm_insert_page(vma,?start,?page))?<?0)??
  • ????????????goto?done;??
  • ??
  • ????????start?+=?PAGE_SIZE;??
  • ????????addr?+=?PAGE_SIZE;??
  • ????????size?-=?PAGE_SIZE;??
  • ????}??
  • ??
  • ????vma->vm_ops?=?&myuvc_vm_ops;??
  • ????vma->vm_private_data?=?buffer;??
  • ????myuvc_vm_open(vma);??
  • ??
  • done:??
  • ????return?ret;??
  • }??
  • ??
  • /*?A12?APP調(diào)用POLL/select來確定緩存是否就緒(有數(shù)據(jù))??
  • ?*?參考?:?uvc_v4l2_poll?
  • ?*/??
  • static?unsigned?int?myuvc_poll(struct?file?*file,?struct?poll_table_struct?*wait)??
  • {??
  • ????struct?myuvc_buffer?*buf;??
  • ????unsigned?int?mask?=?0;??
  • ??????
  • ????/*?從mainqueuq中取出第1個(gè)緩沖區(qū)?*/??
  • ??
  • ????/*判斷它的狀態(tài),?如果未就緒,?休眠?*/??
  • ??
  • ????if?(list_empty(&myuvc_queue.mainqueue))?{??
  • ????????mask?|=?POLLERR;??
  • ????????goto?done;??
  • ????}??
  • ??????
  • ????buf?=?list_first_entry(&myuvc_queue.mainqueue,?struct?myuvc_buffer,?stream);??
  • ??
  • ????poll_wait(file,?&buf->wait,?wait);??
  • ????if?(buf->state?==?VIDEOBUF_DONE?||??
  • ????????buf->state?==?VIDEOBUF_ERROR)??
  • ????????mask?|=?POLLIN?|?POLLRDNORM;??
  • ??????
  • done:??
  • ????return?mask;??
  • }??
  • ??
  • /*?A18?關(guān)閉?*/??
  • static?int?myuvc_vidioc_streamoff(struct?file?*file,?void?*priv,?enum?v4l2_buf_type?t);??
  • static?int?myuvc_close(struct?file?*file)??
  • {??
  • ????myuvc_vidioc_streamoff(NULL,?NULL,?0);??
  • ????return?0;??
  • }??
  • ??
  • 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?void?myuvc_release(struct?video_device?*vdev)??
  • {??
  • }??
  • ??
  • ??
  • static?int?myuvc_probe(struct?usb_interface?*intf,??
  • ?????????????const?struct?usb_device_id?*id)??
  • {??
  • ????static?int?cnt?=?0;??
  • ????struct?usb_device?*dev?=?interface_to_usbdev(intf);??
  • ????int?ret;??
  • ??
  • ????myuvc_udev?=?dev;??
  • ??
  • ????printk("myuvc_probe?:?cnt?=?%d\n",?cnt++);??
  • ??
  • ????if?(cnt?==?1)??
  • ????{??
  • ????????myuvc_control_intf?=?intf->cur_altsetting->desc.bInterfaceNumber;??
  • ????}??
  • ????else?if?(cnt?==?2)??
  • ????{??
  • ????????myuvc_streaming_intf?=?intf->cur_altsetting->desc.bInterfaceNumber;??
  • ????}??
  • ??
  • ????if?(cnt?==?2)??
  • ????{??
  • ????????/*?1.?分配一個(gè)video_device結(jié)構(gòu)體?*/??
  • ????????myuvc_vdev?=?video_device_alloc();??
  • ??
  • ????????/*?2.?設(shè)置?*/??
  • ????????/*?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);??
  • ??
  • ????????/*?為了確定帶寬,使用哪一個(gè)setting?*/??
  • ????????/*?a.?測試參數(shù)?*/??
  • ????????ret?=?myuvc_try_streaming_params(&myuvc_params);??
  • ????????printk("myuvc_try_streaming_params?ret?=?%d\n",?ret);??
  • ??
  • ????????/*?b.?取出參數(shù)?*/??
  • ????????ret?=?myuvc_get_streaming_params(&myuvc_params);??
  • ????????printk("myuvc_get_streaming_params?ret?=?%d\n",?ret);??
  • ??
  • ????????/*?c.?設(shè)置參數(shù)?*/??
  • ????????ret?=?myuvc_set_streaming_params(&myuvc_params);??
  • ????????printk("myuvc_set_streaming_params?ret?=?%d\n",?ret);??
  • ??????????
  • ????????myuvc_print_streaming_params(&myuvc_params);??
  • ??
  • ????}??
  • ??????
  • ??????
  • ????return?0;??
  • }??
  • ??
  • 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);??
  • ????}??
  • ??????
  • }??
  • ??
  • static?struct?usb_device_id?myuvc_ids[]?=?{??
  • ????/*?Generic?USB?Video?Class?*/??
  • ????{?USB_INTERFACE_INFO(USB_CLASS_VIDEO,?1,?0)?},??/*?VideoControl?Interface?*/??
  • ????{?USB_INTERFACE_INFO(USB_CLASS_VIDEO,?2,?0)?},??/*?VideoStreaming?Interface?*/??
  • ????{}??
  • };??
  • ??
  • /*?1.?分配usb_driver?*/??
  • /*?2.?設(shè)置?*/??
  • static?struct?usb_driver?myuvc_driver?=?{??
  • ????.name???????=?"myuvc",??
  • ????.probe??????=?myuvc_probe,??
  • ????.disconnect?=?myuvc_disconnect,??
  • ????.id_table???=?myuvc_ids,??
  • };??
  • ??
  • static?int?myuvc_init(void)??
  • {??
  • ????/*?3.?注冊?*/??
  • ????usb_register(&myuvc_driver);??
  • ????return?0;??
  • }??
  • ??
  • static?void?myuvc_exit(void)??
  • {??
  • ????usb_deregister(&myuvc_driver);??
  • }??
  • ??
  • module_init(myuvc_init);??
  • module_exit(myuvc_exit);??
  • ??
  • MODULE_LICENSE("GPL");??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • </media></media></media></asm></asm></linux></linux></linux></linux></linux></linux></linux></linux>?
  • 總結(jié)

    以上是生活随笔為你收集整理的自己写的uvc驱动支持IP2977/ip2970的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。