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} };
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 ("Failed to configure camera"); goto error; } /* Init video stuff */ spca50x->vdev = video_device_alloc (); //设备控制块内存分配 if (!spca50x->vdev) goto error; 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) < 0) { //video设备注册 err ("video_register_device failed"); goto error; } spca50x->present = 1; if (spca50x->force_rgb) info ("data format set to RGB"); spca50x->task.sync = 0; spca50x->task.routine = auto_bh; spca50x->task.data = spca50x; spca50x->bh_requested = 0; MOD_DEC_USE_COUNT; //增加模块使用数 return spca50x; //返回数剧结构 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; return NULL; nodevice: return NULL; }
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系统调用。
其关键的数据结构如下:
static struct video_device spca50x_template = { .owner = THIS_MODULE, .name = "SPCA5XX USB Camera", .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_SPCA5XX, .fops = &spca5xx_fops, }; static struct file_operations spca5xx_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,//文件定位功能未实现 };