失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > linux usb摄像头 源码 Linux USB摄像头驱动实现源码分析

linux usb摄像头 源码 Linux USB摄像头驱动实现源码分析

时间:2024-04-11 08:21:33

相关推荐

linux usb摄像头 源码 Linux USB摄像头驱动实现源码分析

Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成:

设备模块的初始化模块和卸载模块,上层软件接口模块,数据传输模块。

具体的模块分析如下:

一、初始化设备模块

该驱动采用了显式的模块初始化和消除函数,即调用module_init来初始化一个模块,并在卸载时调用moduel-exit函数

其具体实现如下:

1、模块初始化:

module_init (usb_spca5xx_init);

static int __init usb_spca5xx_init (void)

{

#ifdef CONFIG_PROC_FS

proc_spca50x_create ();//建立PROC设备文件

#endif /* CONFIG_PROC_FS */

if (usb_register (&spca5xx_driver) < 0) //注册USB设备驱动

return -1;

info ("spca5xx driver %s registered", version);

return 0;

}

2、模块卸载:

module_exit (usb_spca5xx_exit);

static void __exit usb_spca5xx_exit (void)

{

usb_deregister (&spca5xx_driver); //注销USB设备驱动

info ("driver spca5xx deregistered");

#ifdef CONFIG_PROC_FS

proc_spca50x_destroy ();//撤消PROC设备文件

#endif /* CONFIG_PROC_FS */

}

关键数据结构USB驱动结构,即插即用功能的实现

static struct usb_driver spca5xx_driver = {

"spca5xx",

spca5xx_probe, //注册设备自我侦测功能

spca5xx_disconnect,//注册设备自我断开功能

{NULL,NULL}

};

用两个函数调用spca5xx_probe 和spca5xx_disconnect来支持USB设备的即插即用功能:

a --spca5xx_probe具体实现如下:

static void * spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)

{

struct usb_interface_descriptor *interface; //USB设备接口描述符

struct usb_spca50x *spca50x; //物理设备数据结构

int err_probe;

int i;

if (dev->descriptor.bNumConfigurations != 1) //探测设备是不是可配置

goto nodevice;

if (ifnum > 0)

goto nodevice;

interface = &dev->actconfig->interface[ifnum].altsetting[0];

MOD_INC_USE_COUNT;

interface = &intf->altsetting[0].desc;

if (interface->bInterfaceNumber > 0)

goto nodevice;

if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL) //分配物理地址空间

{

err ("couldn't kmalloc spca50x struct");

goto error;

}

memset (spca50x, 0, sizeof (struct usb_spca50x));

spca50x->dev = dev;

spca50x->iface = interface->bInterfaceNumber;

if ((err_probe = spcaDetectCamera (spca50x)) < 0) //具体物理设备查找,匹配厂商号,设备号(在子程序中)

{

err (" Devices not found !! ");

goto error;

}

PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name)

for (i = 0; i < SPCA50X_NUMFRAMES; i++)

init_waitqueue_head (&spca50x->frame[i].wq); //初始化帧等待队列

init_waitqueue_head (&spca50x->wq); //初始化驱动等待队列

if (!spca50x_configure (spca50x)) //物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号

{

spca50x->user = 0;

init_MUTEX (&spca50x->lock); //信号量初始化

init_MUTEX (&spca50x->buf_lock);

spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;

spca50x->buf_state = BUF_NOT_ALLOCATED;

}

else

{

err("Failedtoconfigurecamera");

gotoerror;

}

/*Initvideostuff*/

spca50x->vdev=video_device_alloc();//设备控制块内存分配

if(!spca50x->vdev)

gotoerror;

memcpy(spca50x->vdev,&spca50x_template,sizeof(spca50x_template));

//系统调用的挂接,在此将驱动实现的系统调用,挂到内核中

video_set_drvdata(spca50x->vdev,spca50x);

if(video_register_device(spca50x->vdev,VFL_TYPE_GRABBER,video_nr)

{

//video设备注册

err("video_register_devicefailed");

gotoerror;

}

spca50x->present=1;

if(spca50x->force_rgb)

info("dataformatsettoRGB");

spca50x->task.sync=0;

spca50x->task.routine=auto_bh;

spca50x->task.data=spca50x;

spca50x->bh_requested=0;

MOD_DEC_USE_COUNT;//增加模块使用数

returnspca50x;//返回数剧结构

error://错误处理

if(spca50x->vdev)

{

if(spca50x->vdev->minor==-1)

video_device_release(spca50x->vdev);

else

video_unregister_device(spca50x->vdev);

spca50x->vdev=NULL;

}

if(spca50x)

{

kfree(spca50x);

spca50x=NULL;

}

MOD_DEC_USE_COUNT;

returnNULL;

nodevice:

returnNULL;

}

b -- Spca5xx_disconnect 的具体实现如下:

static void spca5xx_disconnect (struct usb_device *dev, void *ptr)

{

struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;

int n;

MOD_INC_USE_COUNT; //增加模块使用数

if (!spca50x)

return;

down (&spca50x->lock); //减少信号量

spca50x->present = 0; //驱动卸载置0

for (n = 0; n < SPCA50X_NUMFRAMES; n++) //标示所有帧ABORTING状态

{

spca50x->frame[n].grabstate = FRAME_ABORTING;

spca50x->curframe = -1;

}

for (n = 0; n < SPCA50X_NUMFRAMES; n++) //唤醒所有等待进程

{

if (waitqueue_active (&spca50x->frame[n].wq))

wake_up_interruptible (&spca50x->frame[n].wq);

if (waitqueue_active (&spca50x->wq))

wake_up_interruptible (&spca50x->wq);

}

spca5xx_kill_isoc(spca50x); //子函数终止URB包的传输

PDEBUG (3,"Disconnect Kill isoc done");

up (&spca50x->lock); //增加信号量

while(spca50x->user) /如果还有进程在使用,进程切换

schedule();

down (&spca50x->lock);

if (spca50x->vdev)

{

video_unregister_device (spca50x->vdev); //注销video设备

usb_driver_release_interface (&spca5xx_driver,&spca50x->dev->actconfig->interface[spca50x->iface]); //端口释放

spca50x->dev = NULL;

}

up (&spca50x->lock);

#ifdef CONFIG_PROC_FS

destroy_proc_spca50x_cam (spca50x); //注销PROC文件

#endif /* CONFIG_PROC_FS */

if (spca50x && !spca50x->user) //释放内存空间

{

spca5xx_dealloc (spca50x);

kfree (spca50x);

spca50x = NULL;

}

MOD_DEC_USE_COUNT; //减少模块记数

PDEBUG (3, "Disconnect complete");

}

二、上层软件接口模块:

该模块通过file_operations数据结构,依据V4L协议规范,实现设备的关键系统调用,实现设备文件化的UNIX系统设计特点。作为摄相头驱动,其功能在于数据采集,而没有向摄相头输出的功能,因此在源码中没有实现write系统调用。

其关键的数据结构如下:

staticstructvideo_devicespca50x_template={

.owner=THIS_MODULE,

.name="SPCA5XXUSBCamera",

.type=VID_TYPE_CAPTURE,

.hardware=VID_HARDWARE_SPCA5XX,

.fops=&spca5xx_fops,

};

staticstructfile_operationsspca5xx_fops={

.owner=THIS_MODULE,

.open=spca5xx_open,//open功能

.release=spca5xx_close,//close功能

.read=spca5xx_read,//read功能

.mmap=spca5xx_mmap,//内存映射功能

.ioctl=spca5xx_ioctl,//文件信息获取

.llseek=no_llseek,//文件定位功能未实现

};

如果觉得《linux usb摄像头 源码 Linux USB摄像头驱动实现源码分析》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。