📄 zc0301_urb.c
字号:
/* This file contains all operatinos for URB * * It's created by WE.XCC at 2008.05.04 *
* Author's E-mail:84318391@163.com
* */#include <linux/module.h>#include <linux/usb.h>#include <linux/types.h>#include <media/v4l2-common.h>#include <linux/videodev.h>#include "zc0301_debug.h"#include "zc0301_struct.h"#include "zc0301_descriptors.h"void zc0301_urb_complete(struct urb *urb){ struct zc0301_device *cam = NULL; struct zc0301_frame *f = NULL; u32 imagesize = 0; static u32 data_length = 0; u8 i = 0; int err = 0; if (urb == NULL) { debug_error("zc0301_urb_complete:urb is null\n"); return; } cam = urb->context; if (urb->status == -ENOENT) //if uses kill, it will enable { debug_error("zc0301_urb_complete:status is -ENOENT\n"); return; } if (cam->d_state & DISCONNECTED) return; if (cam->d_state & MISCONFIGED) { wake_up_interruptible(&cam->wait_frame); return; } if (cam->s_state == STREAM_OFF || list_empty(&cam->inqueue)) goto resubmit; f = list_entry(cam->inqueue.next, struct zc0301_frame, queue); imagesize = 640 * 480 * 8 / 8; for (i = 0; i < ZC0301_PACKETS; i++) { unsigned int len = 0, status = 0; void *pos = NULL; u16 *soi = NULL; u8 sof = 0; len = urb->iso_frame_desc[i].actual_length; status = urb->iso_frame_desc[i].status; pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; if (status) { debug_error("zc0301_urb_complete:urb's packet's status is wrong\n"); f->f_state = F_ERROR; continue; } sof = (*(soi = pos) == 0xd8ff); //if I have manual, I can understand it/start_of_frame: if (sof) { f->f_state = F_GRABBING; do_gettimeofday(&f->buf.timestamp); //I don't know the function //if I clear it, the driver also works well } if (f->f_state == F_GRABBING) { if (sof && data_length) goto end_of_frame; if (data_length + len > imagesize) { debug_error("exceeded imagesize\n"); f->f_state = F_ERROR; continue; } memcpy(f->bufmem + data_length, pos, len); data_length += len; if (data_length == imagesize) {end_of_frame: f->f_state = F_DONE; f->buf.bytesused = data_length; data_length = 0; spin_lock(&cam->queue_lock); list_move_tail(&f->queue, &cam->outqueue); //this if-else is so classical, it can speed up the display //the thought like DMA if (list_empty(&cam->inqueue)) f = NULL; else f = list_entry(cam->inqueue.next, struct zc0301_frame, queue); spin_unlock(&cam->queue_lock); wake_up_interruptible_nr(&cam->wait_frame, 1); if (f == NULL) goto resubmit; else goto start_of_frame; } } }resubmit: urb->dev = cam->usbdev; err = usb_submit_urb(urb, GFP_ATOMIC); //takes GFP_ATOMIC if in urb complete if (err < 0) debug_error("resubmit urb failed\n"); return;}int zc0301_urb_start(struct zc0301_device *cam){ struct usb_device *udev = NULL; struct usb_host_interface *altsetting = NULL; u16 psz = 0; s8 i = 0, j = 0; int err = 0, flag = 0; if (cam == NULL) { debug_error("zc0301_urb_start:cam is null\n"); return -ENODEV; } //debug_param("%s\n", __FUNCTION__); udev = cam->usbdev; altsetting = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 7); psz = le16_to_cpu(altsetting->endpoint[0].desc.wMaxPacketSize); do { for (i = 0; i < ZC0301_URBS; i++) { cam->transfer_buffer[i] = kzalloc(ZC0301_PACKETS * psz, GFP_KERNEL); if (cam->transfer_buffer[i] == NULL) { debug_error("zc0301_urb_start:alloc transfer buffer failed\n"); err = -ENOMEM; flag = 1; break; } } for (i = 0; i < ZC0301_URBS; i++) { cam->urb[i] = usb_alloc_urb(ZC0301_PACKETS, GFP_KERNEL); if (cam->urb[i] == NULL) { debug_error("zc0301_urb_start:usb_alloc_urb failed\n"); err = -ENOMEM; flag = 1; break; } cam->urb[i]->dev = udev; cam->urb[i]->context = cam; cam->urb[i]->pipe = usb_rcvisocpipe(udev, 1); cam->urb[i]->interval = 1; cam->urb[i]->transfer_flags = URB_ISO_ASAP; cam->urb[i]->transfer_buffer = cam->transfer_buffer[i]; cam->urb[i]->complete = zc0301_urb_complete; cam->urb[i]->number_of_packets = ZC0301_PACKETS; cam->urb[i]->transfer_buffer_length = ZC0301_PACKETS * psz; for (j = 0; j < ZC0301_PACKETS; j++) { cam->urb[i]->iso_frame_desc[j].offset = j * psz; cam->urb[i]->iso_frame_desc[j].length = psz; } //debug_info("zc0301_urb_start:urb[] alloc successed\n"); } err = usb_set_interface(udev, 0, 7); if (err) { debug_error("zc0301_urb_start:open usb interface failed\n"); flag = 1; break; } for (i = 0; i < ZC0301_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); if (err) { debug_error("zc0301_urb_start:usb_submit_urb failed\n"); flag = 1; break; } } }while(0); if (flag) { debug_error("zc0301_urb_start:There is some wrong with urb start!\n"); for (i = 0; i < ZC0301_URBS && cam->transfer_buffer[i]; i++) kfree(cam->transfer_buffer[i]); for (i = 0; i < ZC0301_URBS && cam->urb[i]; i++) usb_free_urb(cam->urb[i]); return err; } return 0;}int zc0301_urb_stop(struct zc0301_device *cam){ struct usb_device *udev = NULL; s8 i = 0; int err = 0; if (cam == NULL) { debug_error("zc0301_urb_stop:cam is null\n"); return -ENODEV; } //debug_param("%s\n", __FUNCTION__); udev = cam->usbdev; if (cam->d_state & DISCONNECTED) { debug_info("zc0301_urb_stop:device has been disconnected\n"); return 0; } for (i = ZC0301_URBS-1; i >= 0; i--) { usb_kill_urb(cam->urb[i]); /*kill and unlink are so different...*/ //usb_unlink_urb(cam->urb[i]); usb_free_urb(cam->urb[i]); kfree(cam->transfer_buffer[i]); } err = usb_set_interface(udev, 0, 0); if (err) { debug_error("zc0301_urb_stop:close usb interface failed\n"); return err; } return 0;}EXPORT_SYMBOL(zc0301_urb_complete);EXPORT_SYMBOL(zc0301_urb_start);EXPORT_SYMBOL(zc0301_urb_stop);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -