标签:
仿照内核的自带UVC(usb video class)驱动程序写的一版简化驱动,仅供学习,实际项目开发中应该尽量使用内核自带的驱动,除非内核自带的驱动不支持此款硬件才需要自己写驱动。
下面就直接上代码了,要根据自己的设备信息修改相关配置参数。
1 #include <linux/kernel.h> 2 #include <linux/list.h> 3 #include <linux/module.h> 4 #include <linux/usb.h> 5 #include <linux/videodev2.h> 6 #include <linux/vmalloc.h> 7 #include <linux/wait.h> 8 #include <linux/mm.h> 9 #include <asm/atomic.h> 10 #include <asm/unaligned.h> 11 12 #include <media/v4l2-common.h> 13 #include <media/v4l2-ioctl.h> 14 #include <media/videobuf-core.h> 15 16 #include "uvcvideo.h" 17 18 #define sheldon_UVC_URBS 3 19 20 21 /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ 22 #define UVC_STREAM_EOH (1 << 7) 23 #define UVC_STREAM_ERR (1 << 6) 24 #define UVC_STREAM_STI (1 << 5) 25 #define UVC_STREAM_RES (1 << 4) 26 #define UVC_STREAM_SCR (1 << 3) 27 #define UVC_STREAM_PTS (1 << 2) 28 #define UVC_STREAM_EOF (1 << 1) 29 #define UVC_STREAM_FID (1 << 0) 30 31 32 struct sheldon_uvc_streaming_control { 33 __u16 bmHint; 34 __u8 bFormatIndex; 35 __u8 bFrameIndex; 36 __u32 dwFrameInterval; 37 __u16 wKeyFrameRate; 38 __u16 wPFrameRate; 39 __u16 wCompQuality; 40 __u16 wCompWindowSize; 41 __u16 wDelay; 42 __u32 dwMaxVideoFrameSize; 43 __u32 dwMaxPayloadTransferSize; 44 __u32 dwClockFrequency; 45 __u8 bmFramingInfo; 46 __u8 bPreferedVersion; 47 __u8 bMinVersion; 48 __u8 bMaxVersion; 49 }; 50 51 52 53 /*参考 drivers/media/video/uvc 下一系列代码*/ 54 55 struct frame_desc { 56 int width; 57 int height; 58 }; 59 60 /* 参考uvc_video_queue定义一些结构体 */ 61 struct sheldon_uvc_buffer { 62 struct v4l2_buffer buf; 63 int state; 64 int vma_use_count; /* 表示是否已经被mmap */ 65 wait_queue_head_t wait; /* APP要读某个缓冲区,如果无数据,在此休眠 */ 66 struct list_head stream; 67 struct list_head irq; 68 }; 69 70 struct sheldon_uvc_queue { 71 void *mem; 72 int count; 73 int buf_size; 74 struct sheldon_uvc_buffer buffer[32]; 75 76 struct urb *urb[32]; 77 char *urb_buffer[32]; 78 dma_addr_t urb_dma[32]; 79 unsigned int urb_size; 80 81 struct list_head mainqueue; /* 供APP消费用 */ 82 struct list_head irqqueue; /* 供底层驱动生产用 */ 83 }; 84 85 static struct sheldon_uvc_queue sheldon_uvc_queue; 86 87 static struct video_device *sheldon_uvc_vdev; 88 static struct usb_device *sheldon_uvc_udev; 89 static int sheldon_uvc_bEndpointAddress = 0x82; //lsusb - 人工确定参数 90 static int sheldon_uvc_streaming_intf; 91 static int sheldon_uvc_control_intf; 92 static int sheldon_uvc_streaming_bAlternateSetting = 1; 93 static struct v4l2_format sheldon_uvc_format; 94 static struct frame_desc framdesc[] = {{640,480},{320,240},{160,120}};//{{640, 480}, {352, 288}, {320, 240}, {176, 144}, {160, 120}}; 95 static int frame_idx = 1; 96 static int bBitsPerPixel = 16; /* lsusb -v -d 0x1e4e: "bBitsPerPixel" */ 97 static int uvc_version = 0x0100; /* lsusb -v -d 0x1e4e: bcdUVC */ 98 static int wMaxPacketSize = 128; 99 static int ProcessingUnitID = 5; 100 101 static struct sheldon_uvc_streaming_control sheldon_uvc_params; 102 103 104 /* A2 参考 uvc_v4l2_do_ioctl */ 105 106 /* sheldonUV_vidioc_querycap :用于判断是否为视频设备*/ 107 static int sheldonUV_vidioc_querycap(struct file *file, void *priv, 108 struct v4l2_capability *cap) 109 { 110 //strcpy(cap->driver, "sheldonUV"); 111 //strcpy(cap->card, "sheldonUV"); 112 //cap->version = 0x0001; 113 //cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 114 115 116 memset(cap, 0, sizeof *cap); 117 strcpy(cap->driver, "sheldonUV"); 118 strcpy(cap->card, "sheldonUV"); 119 120 cap->version = 1; 121 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 122 123 return 0; 124 } 125 126 127 /* A3 列举支持哪种格式 128 * 参考: uvc_fmts 数组 129 */ 130 static int sheldonUV_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 131 struct v4l2_fmtdesc *f) 132 { 133 /* 人工查看描述符可知我们用的摄像头只支持1种格式 */ 134 if (f->index >= 1) 135 return -EINVAL; 136 137 /* 支持什么格式呢? 138 * 查看VideoStreaming Interface的描述符, 139 * ‘Y‘‘U‘‘Y‘‘V‘ 140 * 得到GUID为"59 55 59 32 00 00 10 00 80 00 00 aa 00 38 9b 71" 141 */ 142 strcpy(f->description, "4:2:2, packed, YUYV"); 143 f->pixelformat = V4L2_PIX_FMT_YUYV; 144 145 return 0; 146 } 147 148 /* A4 返回当前所使用的格式 */ 149 static int sheldonUV_vidioc_get_fmt_vid_cap(struct file *file, void *priv, 150 struct v4l2_format *f) 151 { 152 memcpy(f, &sheldon_uvc_format, sizeof(sheldon_uvc_format)); 153 return (0); 154 } 155 156 /* A5 测试驱动程序是否支持某种格式 ,强制设置为第一种格式 157 * 参考: uvc_v4l2_try_format 158 * sheldon_vivi_vidioc_try_fmt_vid_cap 159 */ 160 161 static int sheldonUV_vidioc_try_fmt_vid_cap(struct file *file, void *priv, 162 struct v4l2_format *f) 163 { 164 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 165 { 166 return -EINVAL; 167 } 168 169 if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) 170 return -EINVAL; 171 172 /* 调整format的width, height, 173 * 计算bytesperline, sizeimage 174 */ 175 176 /* 人工查看描述符, 确定支持哪几种分辨率 */ 177 f->fmt.pix.width = framdesc[frame_idx].width; 178 f->fmt.pix.height = framdesc[frame_idx].height; 179 f->fmt.pix.bytesperline = 180 (f->fmt.pix.width * bBitsPerPixel) >> 3; 181 f->fmt.pix.sizeimage = 182 f->fmt.pix.height * f->fmt.pix.bytesperline; 183 184 185 return 0; 186 } 187 188 189 190 /* A6 如果支持这种格式,则进行设置-参考 vivi_vidioc_s_fmt_vid_cap*/ 191 static int sheldonUV_vidioc_set_fmt_vid_cap(struct file *file, void *priv, 192 struct v4l2_format *f) 193 { 194 int ret = sheldonUV_vidioc_try_fmt_vid_cap(file, NULL, f); 195 if (ret < 0) 196 return ret; 197 198 memcpy(&sheldon_uvc_format, f, sizeof(sheldon_uvc_format)); 199 200 return 0;// ret; 201 } 202 203 static int sheldon_uvc_free_buffers(void) 204 { 205 if (sheldon_uvc_queue.mem) 206 { 207 vfree(sheldon_uvc_queue.mem); 208 memset(&sheldon_uvc_queue, 0, sizeof(sheldon_uvc_queue)); 209 sheldon_uvc_queue.mem = NULL; 210 } 211 return 0; 212 } 213 214 215 /* A7 APP 调用该ioctl让驱动程分配若干个缓存,APP将从这些缓存中读到视频数据 216 * 参考: uvc_alloc_buffers 217 */ 218 static int sheldonUV_vidioc_reqbufs(struct file *file, void *priv, 219 struct v4l2_requestbuffers *p) 220 { 221 int nbuffers = p->count; 222 int bufsize = PAGE_ALIGN(sheldon_uvc_format.fmt.pix.sizeimage); 223 unsigned int i; 224 void *mem = NULL; 225 int ret; 226 227 if ((ret = sheldon_uvc_free_buffers()) < 0) 228 goto done; 229 230 /* Bail out if no buffers should be allocated. */ 231 if (nbuffers == 0) 232 goto done; 233 234 /* Decrement the number of buffers until allocation succeeds. */ 235 for (; nbuffers > 0; --nbuffers) { 236 mem = vmalloc_32(nbuffers * bufsize); 237 if (mem != NULL) 238 break; 239 } 240 241 if (mem == NULL) { 242 ret = -ENOMEM; 243 goto done; 244 } 245 246 /* 这些缓存是一次性作为一个整体来分配的 */ 247 memset(&sheldon_uvc_queue, 0, sizeof(sheldon_uvc_queue)); 248 249 INIT_LIST_HEAD(&sheldon_uvc_queue.mainqueue); 250 INIT_LIST_HEAD(&sheldon_uvc_queue.irqqueue); 251 252 for (i = 0; i < nbuffers; ++i) { 253 sheldon_uvc_queue.buffer[i].buf.index = i; 254 sheldon_uvc_queue.buffer[i].buf.m.offset = i * bufsize; 255 sheldon_uvc_queue.buffer[i].buf.length = sheldon_uvc_format.fmt.pix.sizeimage; 256 sheldon_uvc_queue.buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 257 sheldon_uvc_queue.buffer[i].buf.sequence = 0; 258 sheldon_uvc_queue.buffer[i].buf.field = V4L2_FIELD_NONE; 259 sheldon_uvc_queue.buffer[i].buf.memory = V4L2_MEMORY_MMAP; 260 sheldon_uvc_queue.buffer[i].buf.flags = 0; 261 sheldon_uvc_queue.buffer[i].state = VIDEOBUF_IDLE; //分配好后为空闲状态 262 init_waitqueue_head(&sheldon_uvc_queue.buffer[i].wait); 263 } 264 265 sheldon_uvc_queue.mem = mem; 266 sheldon_uvc_queue.count = nbuffers; 267 sheldon_uvc_queue.buf_size = bufsize; 268 ret = nbuffers; 269 270 done: 271 return ret; 272 } 273 274 275 276 /*A8 查询buffer状态,获得偏移值,app可以调用mmap*/ 277 static int sheldonUV_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) 278 { 279 int ret = 0; 280 281 if (v4l2_buf->index >= sheldon_uvc_queue.count) { 282 ret = -EINVAL; 283 goto done; 284 } 285 286 memcpy(v4l2_buf, &sheldon_uvc_queue.buffer[v4l2_buf->index].buf, sizeof(*v4l2_buf)); 287 288 /* 更新flags */ 289 if (sheldon_uvc_queue.buffer[v4l2_buf->index].vma_use_count) 290 v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; 291 292 293 switch (sheldon_uvc_queue.buffer[v4l2_buf->index].state) { 294 case VIDEOBUF_ERROR: 295 case VIDEOBUF_DONE: 296 v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; 297 break; 298 case VIDEOBUF_QUEUED: 299 case VIDEOBUF_ACTIVE: 300 v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; 301 break; 302 case VIDEOBUF_IDLE: 303 default: 304 break; 305 } 306 307 done: 308 return ret; 309 } 310 311 312 /* A10 把缓冲区放入队列, 底层的硬件操作函数将会把数据放入这个队列的缓存 313 * 参考: uvc_queue_buffer 314 */ 315 static int sheldonUV_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) 316 { 317 struct sheldon_uvc_buffer *buf; 318 319 /* 0. APP传入的v4l2_buf可能有问题, 要做判断 */ 320 321 if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 322 v4l2_buf->memory != V4L2_MEMORY_MMAP) { 323 return -EINVAL; 324 } 325 326 if (v4l2_buf->index >= sheldon_uvc_queue.count) { 327 return -EINVAL; 328 } 329 330 buf = &sheldon_uvc_queue.buffer[v4l2_buf->index]; 331 332 if (buf->state != VIDEOBUF_IDLE) { 333 return -EINVAL; 334 } 335 336 337 /* 1. 修改状态 */ 338 buf->state = VIDEOBUF_QUEUED; 339 buf->buf.bytesused = 0; 340 341 /* 2. 放入2个队列 */ 342 /* 队列1: 供APP使用 343 * 当缓冲区没有数据时,放入mainqueue队列 344 * 当缓冲区有数据时, APP从mainqueue队列中取出 345 */ 346 list_add_tail(&buf->stream, &sheldon_uvc_queue.mainqueue); 347 348 /* 队列2: 供产生数据的函数使用 349 * 当采集到数据时,从irqqueue队列中取出第1个缓冲区,存入数据 350 */ 351 list_add_tail(&buf->irq, &sheldon_uvc_queue.irqqueue); 352 353 return 0; 354 355 } 356 357 358 static void sheldon_uvc_print_streaming_params(struct sheldon_uvc_streaming_control *ctrl) 359 { 360 printk("video params:\n"); 361 printk("bmHint = %d\n", ctrl->bmHint); 362 printk("bFormatIndex = %d\n", ctrl->bFormatIndex); 363 printk("bFrameIndex = %d\n", ctrl->bFrameIndex); 364 printk("dwFrameInterval = %d\n", ctrl->dwFrameInterval); 365 printk("wKeyFrameRate = %d\n", ctrl->wKeyFrameRate); 366 printk("wPFrameRate = %d\n", ctrl->wPFrameRate); 367 printk("wCompQuality = %d\n", ctrl->wCompQuality); 368 printk("wCompWindowSize = %d\n", ctrl->wCompWindowSize); 369 printk("wDelay = %d\n", ctrl->wDelay); 370 printk("dwMaxVideoFrameSize = %d\n", ctrl->dwMaxVideoFrameSize); 371 printk("dwMaxPayloadTransferSize = %d\n", ctrl->dwMaxPayloadTransferSize); 372 printk("dwClockFrequency = %d\n", ctrl->dwClockFrequency); 373 printk("bmFramingInfo = %d\n", ctrl->bmFramingInfo); 374 printk("bPreferedVersion = %d\n", ctrl->bPreferedVersion); 375 printk("bMinVersion = %d\n", ctrl->bMinVersion); 376 printk("bMinVersion = %d\n", ctrl->bMinVersion); 377 } 378 379 380 /* 参考: uvc_get_video_ctrl 381 (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) 382 static int uvc_get_video_ctrl(struct uvc_video_device *video, 383 struct uvc_streaming_control *ctrl, int probe, __u8 query) 384 */ 385 static int sheldon_uvc_get_streaming_params(struct sheldon_uvc_streaming_control *ctrl) 386 { 387 __u8 *data; 388 __u16 size; 389 int ret; 390 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 391 unsigned int pipe; 392 393 size = uvc_version >= 0x0110 ? 34 : 26; 394 data = kmalloc(size, GFP_KERNEL); 395 if (data == NULL) 396 return -ENOMEM; 397 398 pipe = (GET_CUR & 0x80) ? usb_rcvctrlpipe(sheldon_uvc_udev, 0) 399 : usb_sndctrlpipe(sheldon_uvc_udev, 0); 400 type |= (GET_CUR & 0x80) ? USB_DIR_IN : USB_DIR_OUT; 401 402 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_CUR, type, VS_PROBE_CONTROL << 8, 403 0 << 8 | sheldon_uvc_streaming_intf, data, size, 5000); 404 405 if (ret < 0) 406 goto done; 407 408 ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); 409 ctrl->bFormatIndex = data[2]; 410 ctrl->bFrameIndex = data[3]; 411 ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]); 412 ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]); 413 ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]); 414 ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]); 415 ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]); 416 ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]); 417 ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); 418 ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); 419 420 if (size == 34) { 421 ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); 422 ctrl->bmFramingInfo = data[30]; 423 ctrl->bPreferedVersion = data[31]; 424 ctrl->bMinVersion = data[32]; 425 ctrl->bMaxVersion = data[33]; 426 } else { 427 //ctrl->dwClockFrequency = video->dev->clock_frequency; 428 ctrl->bmFramingInfo = 0; 429 ctrl->bPreferedVersion = 0; 430 ctrl->bMinVersion = 0; 431 ctrl->bMaxVersion = 0; 432 } 433 434 done: 435 kfree(data); 436 437 return (ret < 0) ? ret : 0; 438 } 439 440 441 /* 参考: uvc_v4l2_try_format ∕uvc_probe_video 442 * uvc_set_video_ctrl(video, probe, 1) 443 */ 444 static int sheldon_uvc_try_streaming_params(struct sheldon_uvc_streaming_control *ctrl) 445 { 446 __u8 *data; 447 __u16 size; 448 int ret; 449 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 450 unsigned int pipe; 451 452 memset(ctrl, 0, sizeof *ctrl); 453 454 ctrl->bmHint = 1; /* dwFrameInterval */ 455 ctrl->bFormatIndex = 1; 456 ctrl->bFrameIndex = frame_idx + 1; 457 ctrl->dwFrameInterval = 333333; 458 459 460 size = uvc_version >= 0x0110 ? 34 : 26; 461 data = kzalloc(size, GFP_KERNEL); 462 463 464 if (data == NULL) 465 return -ENOMEM; 466 467 468 *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); 469 data[2] = ctrl->bFormatIndex; 470 data[3] = ctrl->bFrameIndex; 471 *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval); 472 *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate); 473 *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate); 474 *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality); 475 *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize); 476 *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay); 477 put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); 478 put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); 479 480 481 if (size == 34) { 482 put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); 483 data[30] = ctrl->bmFramingInfo; 484 data[31] = ctrl->bPreferedVersion; 485 data[32] = ctrl->bMinVersion; 486 data[33] = ctrl->bMaxVersion; 487 } 488 489 490 pipe = (SET_CUR & 0x80) ? usb_rcvctrlpipe(sheldon_uvc_udev, 0) 491 : usb_sndctrlpipe(sheldon_uvc_udev, 0); 492 493 494 type |= (SET_CUR & 0x80) ? USB_DIR_IN : USB_DIR_OUT; 495 496 ret = usb_control_msg(sheldon_uvc_udev, pipe, SET_CUR, type, VS_PROBE_CONTROL << 8, 497 0 << 8 | sheldon_uvc_streaming_intf, data, size, 5000); 498 499 500 kfree(data); 501 502 return (ret < 0) ? ret : 0; 503 504 } 505 506 507 /* 参考: uvc_v4l2_try_format ∕uvc_probe_video 508 * uvc_set_video_ctrl(video, probe, 1) 509 */ 510 static int sheldon_uvc_set_streaming_params(struct sheldon_uvc_streaming_control *ctrl) 511 { 512 __u8 *data; 513 __u16 size; 514 int ret; 515 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 516 unsigned int pipe; 517 518 size = uvc_version >= 0x0110 ? 34 : 26; 519 data = kzalloc(size, GFP_KERNEL); 520 if (data == NULL) 521 return -ENOMEM; 522 523 *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); 524 data[2] = ctrl->bFormatIndex; 525 data[3] = ctrl->bFrameIndex; 526 *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval); 527 *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate); 528 *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate); 529 *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality); 530 *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize); 531 *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay); 532 put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); 533 put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); 534 535 if (size == 34) { 536 put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); 537 data[30] = ctrl->bmFramingInfo; 538 data[31] = ctrl->bPreferedVersion; 539 data[32] = ctrl->bMinVersion; 540 data[33] = ctrl->bMaxVersion; 541 } 542 543 pipe = (SET_CUR & 0x80) ? usb_rcvctrlpipe(sheldon_uvc_udev, 0) 544 : usb_sndctrlpipe(sheldon_uvc_udev, 0); 545 type |= (SET_CUR & 0x80) ? USB_DIR_IN : USB_DIR_OUT; 546 547 ret = usb_control_msg(sheldon_uvc_udev, pipe, SET_CUR, type, VS_COMMIT_CONTROL << 8, 548 0 << 8 | sheldon_uvc_streaming_intf, data, size, 5000); 549 550 kfree(data); 551 552 return (ret < 0) ? ret : 0; 553 554 } 555 556 557 static void sheldon_uvc_uninit_urbs(void) 558 { 559 int i; 560 for (i = 0; i < sheldon_UVC_URBS; ++i) { 561 if (sheldon_uvc_queue.urb_buffer[i]) 562 { 563 usb_buffer_free(sheldon_uvc_udev, sheldon_uvc_queue.urb_size, sheldon_uvc_queue.urb_buffer[i], sheldon_uvc_queue.urb_dma[i]); 564 sheldon_uvc_queue.urb_buffer[i] = NULL; 565 } 566 567 if (sheldon_uvc_queue.urb[i]) 568 { 569 usb_free_urb(sheldon_uvc_queue.urb[i]); 570 sheldon_uvc_queue.urb[i] = NULL; 571 } 572 } 573 } 574 575 576 /* 参考: uvc_video_complete / uvc_video_decode_isoc */ 577 static void sheldon_uvc_video_complete(struct urb *urb) 578 { 579 u8 *src; 580 u8 *dest; 581 int ret, i; 582 int len; 583 int maxlen; 584 int nbytes; 585 struct sheldon_uvc_buffer *buf; 586 587 switch (urb->status) { 588 case 0: 589 break; 590 591 default: 592 printk("Non-zero status (%d) in video " 593 "completion handler.\n", urb->status); 594 return; 595 } 596 597 /* 从irqqueue队列中取出第1个缓冲区 */ 598 if (!list_empty(&sheldon_uvc_queue.irqqueue)) //如果队列不空 599 { 600 buf = list_first_entry(&sheldon_uvc_queue.irqqueue, struct sheldon_uvc_buffer, irq); 601 602 603 for (i = 0; i < urb->number_of_packets; ++i) { 604 if (urb->iso_frame_desc[i].status < 0) { 605 printk("USB isochronous frame " 606 "lost (%d).\n", urb->iso_frame_desc[i].status); 607 continue; 608 } 609 610 src = urb->transfer_buffer + urb->iso_frame_desc[i].offset; //源 611 612 dest = sheldon_uvc_queue.mem + buf->buf.m.offset + buf->buf.bytesused; //目的 613 614 len = urb->iso_frame_desc[i].actual_length; //整个数据长度 615 /* 判断数据是否有效 */ 616 /* URB数据含义: 617 * data[0] : 头部长度 618 * data[1] : 错误状态 619 */ 620 if (len < 2 || src[0] < 2 || src[0] > len) 621 continue; 622 623 /* Skip payloads marked with the error bit ("error frames"). */ 624 if (src[1] & UVC_STREAM_ERR) { 625 printk("Dropping payload (error bit set).\n"); 626 continue; 627 } 628 629 /* 除去头部后的数据长度 */ 630 len -= src[0]; 631 632 /* 缓冲区最多还能存多少数据 */ 633 maxlen = buf->buf.length - buf->buf.bytesused; 634 nbytes = min(len, maxlen); 635 636 /* 复制数据 */ 637 memcpy(dest, src + src[0], nbytes); 638 buf->buf.bytesused += nbytes; 639 640 /* 判断一帧数据是否已经全部接收到 */ 641 if (len > maxlen) { 642 buf->state = VIDEOBUF_DONE; 643 } 644 645 /* Mark the buffer as done if the EOF marker is set. */ 646 if (src[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) { 647 printk("Frame complete (EOF found).\n"); 648 if (len == 0) 649 printk("EOF in empty payload.\n"); 650 buf->state = VIDEOBUF_DONE; 651 } 652 653 } 654 655 /* 当接收完一帧数据, 656 * 从irqqueue中删除这个缓冲区 657 * 唤醒等待数据的进程 658 */ 659 if (buf->state == VIDEOBUF_DONE || 660 buf->state == VIDEOBUF_ERROR) 661 { 662 list_del(&buf->irq); 663 wake_up(&buf->wait); 664 } 665 } 666 667 /* 再次提交URB */ 668 if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { 669 printk("Failed to resubmit video URB (%d).\n", ret); 670 } 671 } 672 673 674 675 /* 参考: uvc_init_video_isoc */ 676 static int sheldon_uvc_alloc_init_urbs(void) 677 { 678 u16 psize; 679 u32 size; 680 int npackets; 681 int i; 682 int j; 683 684 struct urb *urb; 685 686 psize = wMaxPacketSize; /* 实时传输端点一次能传输的最大字节数 */ 687 size = sheldon_uvc_params.dwMaxVideoFrameSize; /* 一帧数据的最大长度 */ 688 npackets = DIV_ROUND_UP(size, psize); 689 if (npackets > 32) 690 npackets = 32; 691 692 size = sheldon_uvc_queue.urb_size = psize * npackets; 693 694 for (i = 0; i < sheldon_UVC_URBS; ++i) { 695 /* 1. 分配usb_buffers */ 696 697 sheldon_uvc_queue.urb_buffer[i] = usb_buffer_alloc( 698 sheldon_uvc_udev, size, 699 GFP_KERNEL | __GFP_NOWARN, &sheldon_uvc_queue.urb_dma[i]); //sheldon_uvc_queue.urb_dma[i]存放分配的物理地址 700 701 /* 2. 分配urb */ 702 sheldon_uvc_queue.urb[i] = usb_alloc_urb(npackets, GFP_KERNEL); 703 704 if (!sheldon_uvc_queue.urb_buffer[i] || !sheldon_uvc_queue.urb[i]) 705 { 706 sheldon_uvc_uninit_urbs(); 707 return -ENOMEM; 708 } 709 710 } 711 712 /* 3. 设置urb */ 713 for (i = 0; i < sheldon_UVC_URBS; ++i) { 714 urb = sheldon_uvc_queue.urb[i]; 715 716 urb->dev = sheldon_uvc_udev; 717 urb->context = NULL; 718 urb->pipe = usb_rcvisocpipe(sheldon_uvc_udev,sheldon_uvc_bEndpointAddress); 719 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; 720 urb->interval = 1; 721 urb->transfer_buffer = sheldon_uvc_queue.urb_buffer[i]; //分配的urb buffer 722 urb->transfer_dma = sheldon_uvc_queue.urb_dma[i]; //分配的urb 物理地址 723 urb->complete = sheldon_uvc_video_complete; //收完数据的中断处理函数 724 urb->number_of_packets = npackets; //要传输的数据次数 725 urb->transfer_buffer_length = size; //总共的数据量 726 727 for (j = 0; j < npackets; ++j) { 728 urb->iso_frame_desc[j].offset = j * psize; //存放每次传输的数据 729 urb->iso_frame_desc[j].length = psize; 730 } 731 732 } 733 734 return 0; 735 } 736 737 738 /*打开视频流 739 * 参考: uvc_video_enable(video, 1): 740 * uvc_commit_video 741 * uvc_init_video 742 */ 743 static int sheldonUV_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) 744 { 745 int ret; 746 747 /* 1. 向USB摄像头设置参数: 比如使用哪个format, 使用这个format下的哪个frame(分辨率) 748 * 参考: uvc_set_video_ctrl / uvc_get_video_ctrl 749 * 1.1 根据一个结构体uvc_streaming_control设置数据包: 可以手工设置,也可以读出后再修改 750 * 1.2 调用usb_control_msg发出数据包 751 */ 752 753 754 755 /* a. 测试参数 */ 756 ret = sheldon_uvc_try_streaming_params(&sheldon_uvc_params); 757 printk("sheldon_uvc_try_streaming_params ret = %d\n", ret); 758 759 760 761 /* b. 取出参数 */ 762 ret = sheldon_uvc_get_streaming_params(&sheldon_uvc_params); 763 printk("sheldon_uvc_get_streaming_params ret = %d\n", ret); 764 765 /* c. 设置参数 */ 766 ret = sheldon_uvc_set_streaming_params(&sheldon_uvc_params); 767 printk("sheldon_uvc_set_streaming_params ret = %d\n", ret); 768 769 sheldon_uvc_print_streaming_params(&sheldon_uvc_params); 770 771 /* d. 设置VideoStreaming Interface所使用的setting 772 * d.1 从sheldon_uvc_params确定带宽 773 * d.2 根据setting的endpoint能传输的wMaxPacketSize 774 * 找到能满足该带宽的setting 775 */ 776 /* 手工确定: 777 * bandwidth = sheldon_uvc_params.dwMaxPayloadTransferSize = 64 778 * 观察lsusb -v -d 0x1e4e:的结果: 779 * wMaxPacketSize 0x0080 1x128 bytes 780 * bAlternateSetting 6 781 */ 782 usb_set_interface(sheldon_uvc_udev, sheldon_uvc_streaming_intf, sheldon_uvc_streaming_bAlternateSetting); 783 784 /* 2. 分配设置URB */ 785 ret = sheldon_uvc_alloc_init_urbs(); 786 if (ret) 787 printk("sheldon_uvc_alloc_init_urbs err : ret = %d\n", ret); 788 789 /* 3. 提交URB以接收数据 */ 790 for (i = 0; i < sheldon_UVC_URBS; ++i) { 791 if ((ret = usb_submit_urb(sheldon_uvc_queue.urb[i], GFP_KERNEL)) < 0) { 792 printk("Failed to submit URB %u (%d).\n", i, ret); 793 sheldon_uvc_uninit_urbs(); 794 return ret; 795 } 796 } 797 798 return 0; 799 } 800 801 802 /*底层的硬件操作函数取出队列的缓存*/ 803 static int sheldonUV_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) 804 { 805 /* APP发现数据就绪后, 从mainqueue里取出这个buffer */ 806 807 struct sheldon_uvc_buffer *buf; 808 int ret = 0; 809 810 if (list_empty(&sheldon_uvc_queue.mainqueue)) { 811 ret = -EINVAL; 812 goto done; 813 } 814 815 buf = list_first_entry(&sheldon_uvc_queue.mainqueue, struct sheldon_uvc_buffer, stream); 816 817 switch (buf->state) { 818 case VIDEOBUF_ERROR: 819 ret = -EIO; 820 case VIDEOBUF_DONE: 821 buf->state = VIDEOBUF_IDLE; 822 break; 823 824 case VIDEOBUF_IDLE: 825 case VIDEOBUF_QUEUED: 826 case VIDEOBUF_ACTIVE: 827 default: 828 ret = -EINVAL; 829 goto done; 830 } 831 832 list_del(&buf->stream); 833 834 done: 835 return ret; 836 } 837 838 839 840 841 842 /* 843 * A14 之前已经通过mmap映射了缓存, APP可以直接读数据 844 * A15 再次调用sheldonUV_vidioc_qbuf把缓存放入队列 845 * A16 poll... 846 */ 847 848 /* A17 停止-关闭视频流 849 * 参考 : uvc_video_enable(video, 0) 850 */ 851 852 static int sheldonUV_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type t) 853 { 854 struct urb *urb; 855 unsigned int i; 856 857 /* 1. kill URB */ 858 for (i = 0; i < sheldon_UVC_URBS; ++i) { 859 if ((urb = sheldon_uvc_queue.urb[i]) == NULL) 860 continue; 861 usb_kill_urb(urb); 862 } 863 864 /* 2. free URB */ 865 sheldon_uvc_uninit_urbs(); 866 867 /* 3. 设置VideoStreaming Interface为setting 0 */ 868 usb_set_interface(sheldon_uvc_udev, sheldon_uvc_streaming_intf, 0); 869 870 return 0; 871 } 872 873 874 /*[下面几个函数实现属性设置]*/ 875 876 /* 877 *Extract the bit string specified by mapping->offset and mapping->size 878 * from the little-endian data stored at ‘data‘ and return the result as 879 * a signed 32bit integer. Sign extension will be performed if the mapping 880 * references a signed data type. 881 */ 882 static __s32 sheldonUV_get_le_value(const __u8 *data) 883 { 884 int bits = 16; 885 int offset = 0; 886 __s32 value = 0; 887 __u8 mask; 888 889 data += offset / 8; 890 offset &= 7; 891 mask = ((1LL << bits) - 1) << offset; 892 893 for (; bits > 0; data++) { 894 __u8 byte = *data & mask; 895 value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); 896 bits -= 8 - (offset > 0 ? offset : 0); 897 offset -= 8; 898 mask = (1 << bits) - 1; 899 } 900 901 /* Sign-extend the value if needed. */ 902 value |= -(value & (1 << (16 - 1))); 903 904 return value; 905 } 906 907 /* Set the bit string specified by mapping->offset and mapping->size 908 * in the little-endian data stored at ‘data‘ to the value ‘value‘. 909 */ 910 static void sheldonUV_set_le_value(__s32 value, __u8 *data) 911 { 912 int bits = 16; 913 int offset = 0; 914 __u8 mask; 915 916 data += offset / 8; 917 offset &= 7; 918 919 for (; bits > 0; data++) { 920 mask = ((1LL << bits) - 1) << offset; 921 *data = (*data & ~mask) | ((value << offset) & mask); 922 value >>= offset ? offset : 8; 923 bits -= 8 - offset; 924 offset = 0; 925 } 926 } 927 928 929 /* 参考:uvc_query_v4l2_ctrl:调用VIDIOC_QUERYCTRL ioctl确定是否支持某个属性 */ 930 int sheldonUV_vidioc_queryctrl (struct file *file, void *fh, 931 struct v4l2_queryctrl *ctrl) 932 { 933 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 934 unsigned int pipe; 935 int ret; 936 u8 data[2]; 937 938 if (ctrl->id != V4L2_CID_BRIGHTNESS) 939 return -EINVAL; 940 941 memset(ctrl, 0, sizeof *ctrl); 942 ctrl->id = V4L2_CID_BRIGHTNESS; 943 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 944 strcpy(ctrl->name, "sheldonUV_BRIGHTNESS"); 945 ctrl->flags = 0; 946 947 pipe = usb_rcvctrlpipe(sheldon_uvc_udev, 0); 948 type |= USB_DIR_IN; 949 950 /* 发起USB传输确定这些值 */ 951 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_MIN, type, PU_BRIGHTNESS_CONTROL << 8, 952 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 953 if (ret != 2) 954 return -EIO; 955 ctrl->minimum = sheldonUV_get_le_value(data); /* Note signedness */ 956 957 958 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_MAX, type, PU_BRIGHTNESS_CONTROL << 8, 959 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 960 if (ret != 2) 961 return -EIO; 962 ctrl->maximum = sheldonUV_get_le_value(data); /* Note signedness */ 963 964 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_RES, type, PU_BRIGHTNESS_CONTROL << 8, 965 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 966 if (ret != 2) 967 return -EIO; 968 ctrl->step = sheldonUV_get_le_value(data); /* Note signedness */ 969 970 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_DEF, type, PU_BRIGHTNESS_CONTROL << 8, 971 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 972 if (ret != 2) 973 return -EIO; 974 ctrl->default_value = sheldonUV_get_le_value(data); /* Note signedness */ 975 976 printk("Brightness: min =%d, max = %d, step = %d, default = %d\n", ctrl->minimum, ctrl->maximum, ctrl->step, ctrl->default_value); 977 978 return 0; 979 } 980 981 /* 参考 : uvc_ctrl_get : 获得属性 */ 982 int sheldonUV_vidioc_g_ctrl (struct file *file, void *fh, 983 struct v4l2_control *ctrl) 984 { 985 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 986 unsigned int pipe; 987 int ret; 988 u8 data[2]; 989 990 if (ctrl->id != V4L2_CID_BRIGHTNESS) 991 return -EINVAL; 992 993 pipe = usb_rcvctrlpipe(sheldon_uvc_udev, 0); 994 type |= USB_DIR_IN; 995 996 ret = usb_control_msg(sheldon_uvc_udev, pipe, GET_CUR, type, PU_BRIGHTNESS_CONTROL << 8, 997 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 998 if (ret != 2) 999 return -EIO; 1000 ctrl->value = sheldonUV_get_le_value(data); /* Note signedness */ 1001 1002 return 0; 1003 } 1004 1005 /* 参考: uvc_ctrl_set/uvc_ctrl_commit : 设置属性*/ 1006 int sheldonUV_vidioc_s_ctrl (struct file *file, void *fh, 1007 struct v4l2_control *ctrl) 1008 { 1009 __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 1010 unsigned int pipe; 1011 int ret; 1012 u8 data[2]; 1013 1014 if (ctrl->id != V4L2_CID_BRIGHTNESS) 1015 return -EINVAL; 1016 1017 sheldonUV_set_le_value(ctrl->value, data); 1018 1019 pipe = usb_sndctrlpipe(sheldon_uvc_udev, 0); 1020 type |= USB_DIR_OUT; 1021 1022 ret = usb_control_msg(sheldon_uvc_udev, pipe, SET_CUR, type, PU_BRIGHTNESS_CONTROL << 8, 1023 ProcessingUnitID << 8 | sheldon_uvc_control_intf, data, 2, 5000); 1024 if (ret != 2) 1025 return -EIO; 1026 1027 return 0; 1028 } 1029 1030 static const struct v4l2_ioctl_ops sheldonUV_ioctl_ops = { 1031 // 表示它是一个摄像头设备 1032 .vidioc_querycap = sheldonUV_vidioc_querycap, 1033 1034 /* 用于列举、获得、测试、设置摄像头的数据的格式 */ 1035 .vidioc_enum_fmt_vid_cap = sheldonUV_vidioc_enum_fmt_vid_cap, 1036 .vidioc_g_fmt_vid_cap = sheldonUV_vidioc_get_fmt_vid_cap, 1037 .vidioc_try_fmt_vid_cap = sheldonUV_vidioc_try_fmt_vid_cap, 1038 .vidioc_s_fmt_vid_cap = sheldonUV_vidioc_set_fmt_vid_cap, 1039 1040 /* 缓冲区操作: 申请/查询/放入队列/取出队列 */ 1041 .vidioc_reqbufs = sheldonUV_vidioc_reqbufs, 1042 .vidioc_querybuf = sheldonUV_vidioc_querybuf, 1043 .vidioc_qbuf = sheldonUV_vidioc_qbuf, 1044 .vidioc_dqbuf = sheldonUV_vidioc_dqbuf, 1045 1046 /* 查询/获得/设置属性 */ 1047 .vidioc_queryctrl = sheldonUV_vidioc_queryctrl, 1048 .vidioc_g_ctrl = sheldonUV_vidioc_g_ctrl, 1049 .vidioc_s_ctrl = sheldonUV_vidioc_s_ctrl, 1050 1051 // 启动/停止 1052 .vidioc_streamon = sheldonUV_vidioc_streamon, 1053 .vidioc_streamoff = sheldonUV_vidioc_streamoff, 1054 }; 1055 1056 1057 1058 static int sheldonUV_open(struct file *file) 1059 { 1060 /* 队列操作2: 初始化 */ 1061 /* videobuf_queue_vmalloc_init(&sheldonUV_vb_vidqueue, &sheldonUV_video_qops, 1062 NULL, &sheldonUV_queue_slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, 1063 sizeof(struct videobuf_buffer), NULL); // 倒数第2个参数是buffer的头部大小 1064 1065 sheldonUV_timer.expires = jiffies + 1; 1066 add_timer(&sheldonUV_timer); 1067 */ 1068 return 0; 1069 } 1070 1071 static void sheldon_uvc_vm_open(struct vm_area_struct *vma) 1072 { 1073 struct sheldon_uvc_buffer *buffer = vma->vm_private_data; 1074 buffer->vma_use_count++; 1075 } 1076 1077 static void sheldon_uvc_vm_close(struct vm_area_struct *vma) 1078 { 1079 struct sheldon_uvc_buffer *buffer = vma->vm_private_data; 1080 buffer->vma_use_count--; 1081 } 1082 1083 1084 1085 1086 static struct vm_operations_struct sheldon_uvc_vm_ops = { 1087 .open = sheldon_uvc_vm_open, 1088 .close = sheldon_uvc_vm_close, 1089 }; 1090 1091 1092 /*映射->应用程序空间,之后app可以直接操作这块 1093 * 参考: uvc_v4l2_mmap 1094 */ 1095 static int sheldonUV_mmap(struct file *file, struct vm_area_struct *vma) 1096 { 1097 struct sheldon_uvc_buffer *buffer; 1098 struct page *page; 1099 unsigned long addr, start, size; 1100 unsigned int i; 1101 int ret = 0; 1102 1103 start = vma->vm_start; 1104 size = vma->vm_end - vma->vm_start; 1105 1106 /* 应用程序调用mmap函数时, 会传入offset参数 1107 * 根据这个offset找出指定的缓冲区 1108 */ 1109 for (i = 0; i < sheldon_uvc_queue.count; ++i) { 1110 buffer = &sheldon_uvc_queue.buffer[i]; 1111 if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) 1112 break; 1113 } 1114 1115 if (i == sheldon_uvc_queue.count || size != sheldon_uvc_queue.buf_size) { 1116 ret = -EINVAL; 1117 goto done; 1118 } 1119 1120 /* 1121 * VM_IO marks the area as being an mmaped region for I/O to a 1122 * device. It also prevents the region from being core dumped. 1123 */ 1124 vma->vm_flags |= VM_IO; 1125 1126 /* 根据虚拟地址找到缓冲区对应的page构体 */ 1127 addr = (unsigned long)sheldon_uvc_queue.mem + buffer->buf.m.offset; 1128 while (size > 0) { 1129 page = vmalloc_to_page((void *)addr); 1130 1131 /* 把此page映射到APP对应的虚拟地址上面 */ 1132 if ((ret = vm_insert_page(vma, start, page)) < 0) 1133 goto done; 1134 1135 start += PAGE_SIZE; 1136 addr += PAGE_SIZE; 1137 size -= PAGE_SIZE; 1138 } 1139 1140 vma->vm_ops = &sheldon_uvc_vm_ops; 1141 vma->vm_private_data = buffer; 1142 sheldon_uvc_vm_open(vma); 1143 1144 done: 1145 return ret; 1146 } 1147 1148 1149 /*APP 调用POLL/select确定缓存数据是否就绪*/ 1150 static unsigned int sheldonUV_poll(struct file *file, struct poll_table_struct *wait) 1151 { 1152 struct sheldon_uvc_buffer *buf; 1153 unsigned int mask = 0; 1154 1155 /* 从mainqueuq中取出第1个缓冲区 */ 1156 1157 /*判断它的状态, 如果未就绪, 休眠 */ 1158 1159 if (list_empty(&sheldon_uvc_queue.mainqueue)) { 1160 mask |= POLLERR; 1161 goto done; 1162 } 1163 1164 buf = list_first_entry(&sheldon_uvc_queue.mainqueue, struct sheldon_uvc_buffer, stream); 1165 1166 poll_wait(file, &buf->wait, wait); 1167 if (buf->state == VIDEOBUF_DONE || 1168 buf->state == VIDEOBUF_ERROR) 1169 mask |= POLLIN | POLLRDNORM; 1170 1171 done: 1172 return mask; 1173 } 1174 1175 1176 static int sheldonUV_close(struct file *file) 1177 { 1178 //del_timer(&sheldonUV_timer); 1179 //videobuf_stop(&sheldonUV_vb_vidqueue); 1180 //videobuf_mmap_free(&sheldonUV_vb_vidqueue); 1181 1182 return 0; 1183 } 1184 1185 1186 static const struct v4l2_file_operations sheldonUV_fops = { 1187 .owner = THIS_MODULE, 1188 .open = sheldonUV_open, 1189 .release = sheldonUV_close, 1190 .mmap = sheldonUV_mmap, 1191 .ioctl = video_ioctl2, /* V4L2 ioctl handler -> sheldonUV_ioctl_ops*/ 1192 .poll = sheldonUV_poll, 1193 }; 1194 1195 1196 1197 1198 static void sheldonUV_release(struct video_device *vdev) 1199 { 1200 } 1201 1202 1203 //probe处理函数,有匹配usb设备时调用 1204 static int sheldon_uvc_probe(struct usb_interface *intf, const struct usb_device_id *id) 1205 { 1206 static int cnt; 1207 1208 //根据interface结构体获得usb_devce结构体,其中包含了设备描述符 1209 struct usb_device *dev = interface_to_usbdev(intf); 1210 //此处需要定义一个描述符结构体 1211 struct usb_device_descriptor *descriptor = &dev->descriptor; 1212 //从usb_device结构体中获得配置描述符相关信息 1213 struct usb_host_config *host_config; 1214 struct usb_config_descriptor *config; 1215 //定义接口联合体描述符结构体,获得 IAD 接口 1216 struct usb_interface_assoc_descriptor *assoc_desc; 1217 //接口描述符 1218 struct usb_interface_descriptor *interface; 1219 //端点描述符 1220 struct usb_endpoint_descriptor *endpoint; 1221 //定义接口设置信息结构体 1222 //struct usb_interface_descriptor *idesc; 1223 1224 1225 int i, j ,k ,l ,m; 1226 unsigned char *buffer; 1227 int buflen; 1228 1229 int desc_len; 1230 //int desc_cnt; 1231 1232 sheldon_uvc_udev = dev; 1233 1234 printk("sheldn_uvc_probe : cnt = %d\n", cnt++); 1235 1236 1237 if (cnt == 1) 1238 { 1239 sheldon_uvc_control_intf = intf->cur_altsetting->desc.bInterfaceNumber; 1240 } 1241 else if(cnt == 2) 1242 { 1243 sheldon_uvc_streaming_intf = intf->cur_altsetting->desc.bInterfaceNumber; 1244 } 1245 1246 if (cnt == 2) 1247 { 1248 /*1.分配一个video_device结构体*/ 1249 sheldon_uvc_vdev = video_device_alloc(); 1250 /*2.设置*/ 1251 /* 2.1 */ 1252 sheldon_uvc_vdev->release = sheldonUV_release; 1253 1254 /* 2.2 */ 1255 sheldon_uvc_vdev->fops = &sheldonUV_fops; 1256 1257 /* 2.3 */ 1258 sheldon_uvc_vdev->ioctl_ops = &sheldonUV_ioctl_ops; 1259 /*3.注册*/ 1260 video_register_device(sheldon_uvc_vdev ,VFL_TYPE_GRABBER, -1); 1261 } 1262 1263 return 0; 1264 } 1265 1266 1267 1268 1269 //disconnect函数,设备断开时调用 1270 static void sheldon_uvc_disconnect(struct usb_interface *intf) 1271 { 1272 static int cnt; 1273 printk("sheldon_uvc_disconnect : cnt = %d\n",cnt++); 1274 1275 if (cnt == 2) 1276 { 1277 video_unregister_device(sheldon_uvc_vdev); 1278 video_device_release(sheldon_uvc_vdev); 1279 } 1280 1281 } 1282 1283 //支持的设备类型信息 1284 static struct usb_device_id sheldon_uvc_ids[] = { 1285 /* Generic USB Video Class */ 1286 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },/*1-视频控制接口*/ 1287 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 2, 0) },/*2-视频流控制接口(被1包含)*/ 1288 {} 1289 }; 1290 1291 1292 1293 //1.分配usb_driver结构体 1294 //2.设置 1295 1296 static struct usb_driver sheldon_uvc_driver = { 1297 .name = "sheldon_UV", 1298 .probe = sheldon_uvc_probe, 1299 .disconnect = sheldon_uvc_disconnect, 1300 .id_table = sheldon_uvc_ids, 1301 }; 1302 1303 1304 static int sheldon_uvc_init(void) 1305 { 1306 //3.注册 1307 printk("sheldon_uvc_init ~\n"); 1308 usb_register(&sheldon_uvc_driver); 1309 return 0; 1310 } 1311 1312 static void sheldon_uvc_exit(void) 1313 { 1314 printk("sheldon_uvc_exit ~\n"); 1315 usb_deregister(&sheldon_uvc_driver); 1316 } 1317 1318 module_init(sheldon_uvc_init); 1319 module_exit(sheldon_uvc_exit); 1320 MODULE_LICENSE("GPL");
标签:
原文地址:http://www.cnblogs.com/blogs-of-lxl/p/5118384.html