linux uvc驱动demo-凯发app官方网站

凯发app官方网站-凯发k8官网下载客户端中心 | | 凯发app官方网站-凯发k8官网下载客户端中心
  • 博客访问: 263914
  • 博文数量: 90
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 665
  • 用 户 组: 普通用户
  • 注册时间: 2018-10-15 14:13
个人简介

搭建一个和linux开发者知识共享和学习的平台

文章分类

全部博文(90)

文章存档

2024年(4)

2023年(24)

2022年(27)

2019年(8)

2018年(27)

相关博文
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·

分类: linux

2022-10-21 15:07:25

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


 




typedef unsigned char   ui_08;
typedef unsigned short  ui_16;
typedef unsigned int    ui_32;
typedef char            si_08;
typedef short           si_16;
typedef int             si_32;






static field_uvc_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;
};


struct field_uvc_buffer
{
struct v4l2_buffer buf;
int state;
int vma_use_count;
wait_queue_head_t wait;
struct list_head stream;
struct list_head irq;
};


struct field_uvc_queue
{
void *mem;
int count;
int buf_size;
struct field_uvc_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;
struct list_head irqqueue;
};


static struct field_uvc_queue field_uvc_queue;
static struct video_device *field_uvc_vdev;
static struct usb_device *field_uvc_udev;
static struct v4l2_format field_uvc_format;


static int field_uvc_video_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
{
memset(cap,0,sizeof(*cap));
strcpy(cap->driver,"fielduvc");
strcpy(cap->card,"fielduvc");
cap->version=1;
cap->capabilities=v4l2_cap_video_capture|v4l2_cap_streaming;
return 0;
}


static int field_uvc_videoc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{
if(f->index>=1)
return -einval;
strcpy(f->description,"4:2:2,packed,yuyv");
f->pixelformat=v4l2_pix_fmt_yuyv;
return 0;
}


static int field_uvc_videoc_get_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
{
memcpy(f,&field_uvc_format,sizeof(field_uvc_format));
return 0;
}


static int field_uvc_videoc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
int nbuffers=p->count;
int bufsize=page_align(field_uvc_format.fmt.pix.sizeimage);
unsigned int i;
void *mem=null;
int ret;

if((ret=field_uvc_free_buffers())<0)
goto done;
if(nbuffers==0)
goto done;
for(;nbuffers>0;--nbuffers)
{
mem=vmalloc_32(nbuffers*bufsize);
if(mem!=null)
break;
}
if(mem==null)
{
ret=-enomem;
goto done;
}
memset(&field_uvc_queue,0,sizeof(field_uvc_queue));
init_list_head(&field_uvc_queue.mainqueue);
init_list_head(&field_uvc_queue.irqqueue);
for(i=0;i {
field_uvc_queue.buffer[i].buf.index=i;
field_uvc_queue.buffer[i].buf.m.offset=i*bufsize;
field_uvc_queue.buffer[i].buf.length=field_uvc_format.fmt.pix.sizeiamge;
field_uvc_queue.buffer[i].buf.type=v4l2_buf_type_video_capture;
field_uvc_queue.buffer[i].buf.sequence=0;
}
}


static int field_uvc_videoc_qbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf)
{
struct field_uvc_buffer *buf;

if(v4l2_buf->type!=v4l2_buf_type_video_capture||v4l2_buf->memory!=v4l2_memory_mmap)
return -einval;
if(v4l2_buf->index>=field_uvc_queue.count)
return -einval;
buf=&field_uvc_queue.buffer[v4l2_buf->index];
if(buf->state!=videobuf_idle)
return -einval;
buf->state=videobuf_queued;
buf->buf.bytesused=0;
list_add_tail(&buf->stream,&field_uvc_queue.mainqueue);
list_add_tail(&buf->irq,&field_uvc_queue.irqqueue);
return 0;
}


static int field_uvc_set_streaming_params(struct field_uvc_streaming_contrl *ctrl)
{
__u8 *data;
__u16 size;
int ret;
__8 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]);
pipe=(set_cur&0x80)?usb_rcvctrlpipe(field_uvc_udev,0):usb_sndctrlpipe(field_uvc_udev,0);
type|=(set_cur&0x80)?usb_dir_in:usb_dir_out;
ret=usb_contrl_msg(field_uvc_udev,pipe,set_cur,type,vs_commit_control<<8,0<<8|field_uvc_streaming_intf,data,size,5000);
kfree(data);
return (ret<0)?ret:0;
}


static void field_uvc_video_complete(struct urb *urb)
{
u8 *src;
u8 *dest;
int ret,i;
int len;
int maxlen;
int nbytes;
struct field_uvc_buffer *buf;

switch(urb->status)
{
case 0:
break;
default:
printk("non-zero status %d in video completion handler.\n",urb->status);
}
//从irqqueue队列中取出第1个缓冲区
if(!list_empty(&field_uvc_queue.irqqueue))
{
buf=list_first_entry(&field_uvc_queue.irqqueue,struct field_uvc_buffer,irq);
for(i=0;inumber_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;
dest=field_uvc_queue.mem buf->buf.m.offset buf->buf.bytesused;
len=urb->iso_frame_desc[i].actual_length;
//urb数据含义: data[0]-头部长度,data[1]-错误状态
if(len<2||src[0]<2||src[0]>len)
continue;
//skip paylaod marked with the error bitops
if(src[1]&uvc_stream_err)
{
printk("dropping payload error bit set");
continue;
}
//除去头部后的数据长度
len-=src[0];
//缓冲区{banned}最佳多还能存多少数据
maxlen=buf->buf.length-buf->buf.bytesused;
nbytes=min(len,maxlen);
//copy data
memcpy(desc,src src[0],nbytes);
buf->buf.bytesused =nbytes;
//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 fount\n");
buf->state=videobuf_done;
}
}
//wake up the waiting process
if(buf->state==videobuf_done||buf->state==videobuf_error)
{
list_del(&buf->irq);
wake_up(&buf->wait);
}
}
if((ret=usb_submit_urb(urb,gfp_atomic))<0)
printk("failed to resubmit urb %d\n",ret);
}


static int field_uvc_alloc_init_urbs(void)
{
u16 psize;
u32 size;
int npackets;
int i,j;
struct urb *urb;

psize=wmaxpacketsize;//实际传输端点一次能传输的{banned}最佳大字节数
size=field_uvc_params.dwmaxvideoframesize;
for(i=0;i {
field_uvc_queue.urb_buffer[i]=usb_buffer_alloc(field_uvc_udev,size,gfp_kernel|__gfp_nowarn,&field_uvc_queue.urb_dma[i]);
field_uvc_queue.urb[i]=usb_alloc_urb(npackets,gfp_kernel);
if(!field_uvc_queue.urb_buffer[i]||!field_uvc_queue.urb[i])
{
field_uvc_uninit_urbs();
return -enomem;
}
}

for(i=0;i {
urb=field_uvc_queue.urb[i];
urb->dev=field_uvc_udev;
urb->context=null;
urb->pipe=usb_rcvisocpipe(field_uvc_udev,field_uvc_bendpointaddress);
urb->transfer_flags=urb_iso_asap|urb_no_transfer_dma_map;
urb->interval=1;
urb->transfer_buffer=field_uvc_queue.urb_buffer[i];
urb->transfer_dma=field_uvc_queue.urb_dma[i];
urb->complete=field_uvc_video_complete;
urb->number_of_packets=npackets;//要传输的数据次数
urb->transfer_buffer_length=size;//总共的数据量
for(j=0;j {
urb->iso_frame_desc[j].offset=j*psize;//存放每次传输的数据
urb->iso_frame_desc[j].length=psize;
}
}
return 0;
}


static void field_uvc_uninit_urbs(void)
{
int i;

for(i=0;i {
if(field_uvc_queue.urb_buffer[i])
{
usb_buffer_free(field_uvc_udev,field_uvc_queue.urb_size,field_uvc_queue.urb_buffer[i],field_uvc_queue.urb_dma[i]);
field_uvc_queue.urb_buffer[i]=null;
}
if(field_uvc_queue.urb[i])
{
usb_free_urb(field_uvc_queue.urb[i]);
field_uvc_queue.urb[i]=null;
}
}
}


static int field_uvc_videoc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf)
{
struct field_uvc_buffer *buf;
int ret=0;

if(list_empty(&field_uvc_queue.mainqueue))
{
ret=-einval;
goto done;
}
buf=list_first_entry(&field_uvc_queue.mainqueue,struct field_uvc_buffer,stream);

}


static int field_uvc_videoc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
int ret;

ret=field_uvc_try_streaming_params(&field_uvc_params);

}


static int fiedl_uvc_videoc_streamoff(struct file *file, void *priv, enum v4l2_buf_type t)
{
struct urb *urb;
unsigned int i;

for(i=0;i {
if(urb=field_uvc_queue.urb[i]==null)
continue;
usb_kill_urb(urb);
}
field_uvc_uinit_urbs();
usb_set_interface(field_uvc_udev,field_uvc_streaming_intf,0);
return 0;
}


static __s32 field_uvc_get_le_value(const __u8 *data)
{
int bits=16;
int offset=0;
__s32 value=0;
__u8 mask;

data =offset/8;
offset&=7;
mask=((1ll< 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< }
value|=-(value&(1<<(16-1)));
return value;
}


static void field_uvc_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< *data=(*data&~mask)|((value< value>>=offset?offset:8;
bits-=8-offset;
offset=0;
}
}


int field_uvc_videoc_queryctrl(struct file *file, void *fn, 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,"field_uvc_brightness");
ctrl->flags=0;
pipe=usb_rcvctrlpipe(field_uvc_udev,0);
type|=usb_dir_in;
ret=usb_contrl_msg(field_uvc_udev,pipe,get_min,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
ctrl->minimum=field_uvc_get_le_value(data);
ret=usb_contrl_msg(field_uvc_udev,pipe,get_max,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
ctrl->maximum=field_uvc_get_le_value(data);
ret=usb_contrl_msg(field_uvc_udev,pipe,get_res,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
ctrl->step=field_uvc_get_le_value(data);
ret=usb_control_msg(field_uvc_udev,pipe,get_def,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
ctrl->default_value=field_uvc_get_le_value(data);
return 0;
}


int field_uvc_videoc_g_ctrl(struct file *file, void fn, 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(field_uvc_udev,0);
type|=usb_dir_in;
ret=usb_control_msg(field_uvc_udev,pipe,get_cur,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
ctrl->value=field_uvc_get_le_value(data);
return 0;
}


int field_uvc_videoc_s_ctrl(struct file *file, void *fn, struct v4l2_conctrol *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;
field_uvc_set_le_value(ctrl->value,data);
pipe=usb_sndctrlpipe(field_uvc_udev,0);
type|=usb_dir_out;
ret=usb_contrl_msg(field_uvc_udev,pipe,set_cur,type,pu_brightness_control<<8,
processingunitid<<8|field_uvc_control_intf,data,2,5000);
if(ret!=2)
return -eio;
return 0;
}


static const struct v4l2_ioctl_ops field_uvc_ioctl_ops = {
.videoc_querycap=field_uvc_videoc_querycap,
.videoc_enum_fmt_vid_cap=field_uvc_videoc_enum_fmt_vid_cap,
.videoc_g_fmt_vid_cap=field_uvc_videoc_get_fmt_vid_cap,
};


static void field_uvc_wm_open(struct vm_area_struct *vma)
{
struct field_uvc_buffer *buffer=vma->vm_private_data;
buffer->vma_use_count ;
}


static void field_uvc_vm_close(struct vm_area_struct *vma)
{
struct field_uvc_buffer *buffer=vma->vm_private_data;
buffer->vma_use_count--;
}


static struct vm_operations_struct field_uvc_vm_ops = {
.open=field_uvc_vm_open,
.close=field_uvc_vm_close,
};


static int field_uvc_mmap(struct file *file, struct vm_area_struct *wma)
{
struct field_uvc_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;

for(i=0;i {
buffer=&field_uvc_queue.buffer[i];
if((buffer->buf.m.offset>>page_shift)==vma_pgoff)
break;
}
if(i==field_uvc_queue.count||size!=field_uvc_queue.buf_size)
{
ret=-einval;
goto done;
}
wma->vm_flags|=vm_io;
addr=(unsigned long)field_uvc_queue.mem buffer->buf.m.offset;
while(size>0)
{
page=vmalloc_to_page((void*)addr);
if((ret=vm_insert_page(vma,start,page))<0)
goto done;
start =page_size;
addr =page_size;
size-=page_size;
}
vma->vm_ops=&field_uvc_vm_ops;
vma->vm_private_data=buffer;
field_uvc_vm_open(vma);
done:
return ret;
}


static unsigned int field_uvc_poll(struct file *file, struct poll_table_struct *wait)
{
struct field_uvc_buffer *buf;
unsigned int mask=0;

if(list_empty(&field_uvc_queue.mainqueue))
{
mask|=pollerr;
goto done;
}
buf=list_first_entry(&field_uvc_queue.mainqueue,struct field uvc_buffer,stream);
poll_wait(file,&buf->wait,wait);
if(buf->state==videobuf_done||buf->state==videobuf_error)
mask|=pollin|pollrdnorm;
done:
return mask;
}


static int field_uvc_close(struct file *file)
{

}


static const struct v4l2_field_operations field_uvc_fops = {
.owner=this_module,
.open=field_uvc_open,
.release=field_uvc_close,
.mmap=field_uvc_mmap,
.ioctl=field_uvc_ioctl,
.poll=field_uvc_poll,
};


static void field_uvc_release(struct video_device *vdev)
{

}


static int field_uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
static int cnt;

//根据interface结构体获得usb_device结构体,其中包含了设备描述符
struct usb_device *dev=interface_to_usbdev(intf);
//设备描述符结构体
struct usb_device_descriptor *descriptor=&dev->descriptor;
//配置描述符
struct usb_host_config *host_config;
struct usb_config_descriptor *config;
//接口联合体描述符,获得iad接口
struct usb_interface_assoc_descriptor *assoc_desc;
//接口描述符
struct usb_interface_descriptor *interface;
//端点描述符
struct usb_endpoint_descriptor *endpoint;

field_uvc_udev=dev;
if(cnt==1)
field_uvc_control_intf=intf->cur_altsetting->desc.binterfacenumber;
else if(cnt==2)
field_uvc_streaming_intf=intf->cur_altsetting->desc.binterfacenumber;
if(cnt==2)
{
field_uvc_udev=video_device_alloc();
field_uvc_udev->release=field_uvc_release;
field_uvc_udev->fops=&field_uvc_fops;
field_uvc_udev->ioctl_ops=&field_uvc_ioctl_ops;
video_register_device(field_uvc_udev,vfl_type_grabber,-1);
}
}


static int uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev=interface_to_usbdev(intf);
struct uvc_device *uvc_dev;

if(id->idvendor && id->idproduct)
printk("probing known uvc device %s (x:x)\n",udev->devpath,id->idvendor,id->idproduct);
else
printk("probing generic uvc device %s\n",udev->devpath);
if((uvc_dev=kzalloc(sizeof(*dev),gfp_kernel)) == null)
return -enomem;

init_list_head(&uvc_dev->entities);
init_list_head(&uvc_dev->chains);
init_list_head(&uvc_dev->streams);
atomic_set(&uvc_dev->nstreams,0);
atomic_set(&uvc_dev->nmappings,0);
mutex_init(&uvc_dev->lock);

uvc_dev->udev=usb_get_dev(udev);
uvc_dev->intf=usb_get_intf(intf);
uvc_dev->intfnum=intf->cur_altsetting->desc.binterfacenumber;
uvc_dev->quirks=(uvc_quirks_param == -1)? id->driver_info : uvc_quirks_param;

if(udev->product!=null)
strlcpy(uvc_dev->name,udev->product,sizeof uvc_dev->name);
else
snprintf(uvc_dev->name,sizeof dev->name,"uvc camera (x:x)",le16_to_cpu(udev->descriptor.idvendor),le16_to_cpu(udev->descriptor.idproduct));
if(uvc_parse_control(uvc_dev) < 0)
{
printk("unable to parse uvc descriptors\n");
goto error;
}
printk("found uvc %u.x device %s (x:x)\n",uvc_dev->uvc_version>>8,uvc_dev->uvc_version&0xff,
udev->product?udev->product:"unnamed",le16_to_cpu(udev->descriptor.idvendor),le16_to_cpu(udev->descriptor.idproduct));
if(uvc_dev->quirks != id->driver_info)
{
printk("forcing device quirks to 0x%x by module parameter for testing purpose\n",uvc_dev->quirks);
printk("please report required quirks to the linux-uvc-devel mailing list\n");
}
if(v4l2_device_register(&intf->dev,&uvc_dev->udev) < 0)
goto error;
}


static void field_uvc_disconnect(struct usb_interface *intf)
{
video_unregister_device(field_uvc_udev);
video_device_release(field_uvc_udev);
}


static struct usb_device_id field_uvc_ids[] = {
{usb_interface_info(usb_class_video,1,0)},
{usb_interface_info(usb_class_video,2,0)},
{}
};


static struct usb_driver field_uvc_driver = {
.name = "field_uvc",
.probe = field_uvc_probe,
.disconnect = field_uvc_disconnect,
.id_table = field_uvc_ids,
};


static int __init field_uvc_init(void)
{
    
usb_register(&field_uvc_driver);

    return 0;    
}


static void __exit field_uvc_exit(void)
{
    usb_deregister(&field_uvc_driver);
}




module_init(field_uvc_init);
module_exit(field_uvc_exit);




module_license("gpl");








阅读(740) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
")); function link(t){ var href= $(t).attr('href'); href ="?url=" encodeuricomponent(location.href); $(t).attr('href',href); //setcookie("returnouturl", location.href, 60, "/"); }
网站地图