框架:
USB总线驱动程序的作用
1.识别USB设备
1.1分配地址
1.2并告诉USB设备(setaddress)
1.3发出命令获取描述符
2.查找并安装对应的设备驱动程序
3.提供USB读写函数
usb总线驱动程序在我们接入USB设备的时候会帮我们构造一个新的usb_device.注册到总线里面来。
本驱动程序总共需要构造
1个usb驱动结构体:usb_driver /*用于操作接入的USB设备*/
2个设备结构体:usb_device /*存储识别后的USB的设备信息*/
video_device /*存储驱动程序对video_device设置和操作函数*/
USB摄像头插入之后,首先是作为一个USB设备被内核和驱动程序识别,USB总线驱动程序会查找到对应的设备驱动程序并调用驱动程序。驱动程序中的usb_drive结构体中的.id_table被调用,识别是否支持该USB设备,如果支持usb_drive结构体中的.probe被调用,驱动程序执行相关的USB设备操作,包括将识别的USB设备信息存放在usb_device结构体中,然后,驱动程序再设置该USB设备的“子”类型是video型设备,并将设置信息存储在video_device结构体中,然后在进行video设备操作。应用程序对USB摄像头设备的函数操作都会通过系统调用转化为对video_device结构体中的成员函数调用
因此本驱动程序应该包含三块内容:1、USB设备的操作;2、video设备的操作;3、USB设备与video设备之间的数据传输???
一、首先是USB设备的操作
1、构造USB设备结构体usb_driver,用于存储识别的usb设备信息和对此USB设备的操作函数,主要包括三个:
. id_table:插入设备时,内核程序会调用结构体中的.id_table,识别该USB设是否支持。
.probe:如果支持该设备类型内核程序会自动调用.probe函数执行具体对该USB设备的操作。
. disconnect:拔出USB设备
static struct video_device *myuvc_udev;
2、设置usb_driver结构体
staticstruct usb_driver myuvc_driver = {
.name ="myuvc",
.probe = myuvc_probe, /*插入设备后,判断是否支持该设备*/
.disconnect = myuvc_disconnect,
.id_table = myuvc_ids,
};
3、注册/卸载usb_driver
static int myuvc_init(void)
{
usb_register(&myuvc_driver);
return0;
}
staticvoid myuvc_exit(void)
{
usb_deregister(&myuvc_driver);
}
4、修饰
module_init(myuvc_init);
module_exit(myuvc_exit);
MODULE_LICENSE("GPL");
以上是USB设备的整体框架
5、编写usb_driver成员函数:. id_table,只支持一种USB设备类型
staticstruct usb_device_id myuvc_ids[] = {
/* Generic USB Video Class */
/*对于VCI和VSI,.prboe都会被调用*/
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO,1, 0) }, /* VCI */
{USB_INTERFACE_INFO(USB_CLASS_VIDEO, 2, 0) }, /* VSI */
{}
};
识别USB设备后调用.probe函数,编写.probe函数代码
structusb_device *myuvc_udev; /*定义全局变量myuvc_udev*/
staticstruct usb_device *myuvc_vdev; /*定义全局变量myuvc_vdev*/
staticint myuvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
staticint cnt = 0;
printk("myuvc_probe: cnt = %d\n", cnt++);
if(cnt == 2){ /* VSI调用时*/
/*从接口获得USB设备信息,并赋给myuvc_udev*/
structusb_device *dev = interface_to_usbdev(intf);
myuvc_udev = dev;
/*申请video_device结构体内存myuvc_vdev*/
myuvc_vdev= video_device_alloc();
/*2. 设置video_device ,APP对USB摄像头的操作都会通过系统调用转
换为执行video_device结构体成员函数的操作*/
myuvc_vdev->release = myuvc_release;
myuvc_vdev->fops = &myuvc_fops;
myuvc_vdev->ioctl_ops = &myuvc_ioctl_ops;
/*3. 注册video_device */
video_register_device(myuvc_vdev,VFL_TYPE_GRABBER, -1)
}
return0;
}
编写 . disconnect
staticvoid 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);
}
}
7. 编写video_device的成员函数,用于对video设备的操作
myuvc_release:/*释放*/
staticvoid myuvc_release(struct video_device *vdev)
{
}
myuvc_ioctl_ops:ioctl是设备驱动程序中对设备I/O通道进行管理的函数,用于向设备发控制和配置命令。包括:数据格式、设置内存、 启动/停止数据传输。
staticint myuvc_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) {
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | /*视频捕捉设备*/
V4L2_CAP_STREAMING; /*获取视频数据的方式ioctl*/
return 0;
}
staticint myuvc_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
structv4l2_fmtdesc *f)
{
return 0;
}
staticint myuvc_vidioc_g_fmt_vid_cap(struct file *file, void *priv, structv4l2_format *f)
{
return (0);
}
staticint myuvc_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
structv4l2_format *f)
{
return 0;
}
staticint myuvc_vidioc_s_fmt_vid_cap(struct file *file, void *priv, /*设置格式*/
structv4l2_format *f)
{
return 0;
}
staticint myuvc_vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
return 0;
}
staticint myuvc_vidioc_querybuf(struct file*file, void *priv, struct v4l2_buffer *p)
{
return 0;
}
staticint myuvc_vidioc_qbuf(struct file *file,void *priv, struct v4l2_buffer *p)
{
return 0;
}
staticint myuvc_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
return 0;
}
staticint myuvc_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
return 0;
}
staticint myuvc_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
return 0;
}
/*APP调用ioctl(cmd)函数时,通过系统调用执行video_device中的video_ioctl2,根据cmd内核程序会转换为执行myuvc_ioctl_ops结构体中的某成员函数*/
staticconst struct v4l2_ioctl_ops myuvc_ioctl_ops = {
// 表示它是一个摄像头设备
.vidioc_querycap = myuvc_vidioc_querycap,
/* 用于列举、获得、测试、设置摄像头的数据的格式*/
.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,
/* 缓冲区操作:申请/查询/放入队列/取出队列*/
.vidioc_reqbufs = myuvc_vidioc_reqbufs,
.vidioc_querybuf = myuvc_vidioc_querybuf,
.vidioc_qbuf = myuvc_vidioc_qbuf,
.vidioc_dqbuf = myuvc_vidioc_dqbuf,
// 启动/停止
.vidioc_streamon = myuvc_vidioc_streamon,
.vidioc_streamoff = myuvc_vidioc_streamoff,
};
myuvc_f