視頻傳輸方式一:以IIC協議,經過IO口傳輸視頻流:框架
視頻傳輸方式二:以usb接口傳輸視頻流:ide
驅動:字符設備驅動函數
怎麼寫驅動程序:構造file_operationsspa
告訴內核code
入口函數orm
出口函數視頻
v4l2驅動框架:核心層 -- > file_operationsblog
硬件相關層:接口
一、將usb攝像頭設備插到裝有虛擬機的pc上,dmesg會打印出一些發現usb攝像頭設備的信息,在內核中grep找到打印信息的具體位置;文檔
二、查找打印信息
三、用source insight或其餘閱讀軟件打開uvc_driver.c文件
3.1 -->struct uvc_driver
--> uvc_probe:
v4l2_device_register // 只是作一些初始化工做,初始化鏈表、自旋鎖、互斥鎖等
uvc_register_chains ---uvc_register_video--video_device video_register_device
---struct video_device *vdev; // 分配video_device結構體,設置並經過video_register_device註冊 video_device結構體有兩個重要的成員 ->fops和->ioctl_ops
struct uvc_device *dev,
vdev->v4l2_dev = &dev->vdev;
vdev->fops = &uvc_fops;
media_device_register
四、在內核中有v4l2-framework.txt文檔能夠參考
五、能夠分析虛擬攝像頭驅動:vivi.c
vivi_init-->vivi_create_instance-->video_device_alloc-->video_register_device-->__video_register_device-->vdev->cdev = cdev_alloc();--> cdev_add()
六、在內核中已經提供了file_operations v4l2_fops 的一些基本函數,因此咱們不須要寫字符設備函數。當應用層調用ioctl函數時,調用file_operations中的ioctl---.unlocked_ioctl = v4l2_ioctl, -->video_usercopy(file, cmd, arg, __video_do_ioctl) -->__video_do_ioctl --> 根據應用層ioctl傳入的參數調用video_device->ioctl_ops中對應的函數
v4l2_ioctl------
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
若是video_device已經被註冊了,就調用video_device裏面的fops函數裏面的unlocked_ioctl函數。
而unlocked_ioctl函數內核中已經寫好了,咱們不須要再寫---video_usercopy
----cmd_input_size(cmd);
----check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
----獲得咱們想要的
static unsigned long cmd_input_size(unsigned int cmd) { /* Size of structure up to and including 'field' */ #define CMDINSIZE(cmd, type, field) \ case VIDIOC_##cmd: \ return offsetof(struct v4l2_##type, field) + \ sizeof(((struct v4l2_##type *)0)->field); switch (cmd) { CMDINSIZE(ENUM_FMT, fmtdesc, type); CMDINSIZE(G_FMT, format, type); CMDINSIZE(QUERYBUF, buffer, length); CMDINSIZE(G_PARM, streamparm, type); CMDINSIZE(ENUMSTD, standard, index); CMDINSIZE(ENUMINPUT, input, index); CMDINSIZE(G_CTRL, control, id); CMDINSIZE(G_TUNER, tuner, index); CMDINSIZE(QUERYCTRL, queryctrl, id); CMDINSIZE(QUERYMENU, querymenu, index); CMDINSIZE(ENUMOUTPUT, output, index); CMDINSIZE(G_MODULATOR, modulator, index); CMDINSIZE(G_FREQUENCY, frequency, tuner); CMDINSIZE(CROPCAP, cropcap, type); CMDINSIZE(G_CROP, crop, type); CMDINSIZE(ENUMAUDIO, audio, index); CMDINSIZE(ENUMAUDOUT, audioout, index); CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); default: return _IOC_SIZE(cmd); } }
和
static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, void * __user *user_ptr, void ***kernel_ptr) { int ret = 0; switch (cmd) { case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: { struct v4l2_buffer *buf = parg; if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { if (buf->length > VIDEO_MAX_PLANES) { ret = -EINVAL; break; } *user_ptr = (void __user *)buf->m.planes; *kernel_ptr = (void *)&buf->m.planes; *array_size = sizeof(struct v4l2_plane) * buf->length; ret = 1; } break; } case VIDIOC_S_EXT_CTRLS: case VIDIOC_G_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: { struct v4l2_ext_controls *ctrls = parg; if (ctrls->count != 0) { if (ctrls->count > V4L2_CID_MAX_CTRLS) { ret = -EINVAL; break; } *user_ptr = (void __user *)ctrls->controls; *kernel_ptr = (void *)&ctrls->controls; *array_size = sizeof(struct v4l2_ext_control) * ctrls->count; ret = 1; } break; } } return ret; }
七、用strace 能夠得到程序執行過程當中的系統調用
strace -o xawtv.log xawtv
xawtv所涉及的系統調用就會記錄在xawtv.log中