============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvcvideo.h

#define UVC_MAX_ISO_PACKETS	1

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvcvideo.h

struct uvc_video_device {
	struct uvc_device *dev;
	struct video_device *vdev;
	atomic_t active;
	unsigned int frozen : 1;

	struct list_head iterms;
	struct uvc_entity *oterm;
	struct uvc_entity *processing;
	struct uvc_entity *selector;
	struct list_head extensions;
	struct mutex ctrl_mutex;

	struct uvc_video_queue queue;

	/* Video streaming object, must always be non-NULL. */
	struct uvc_streaming *streaming;

	void (*decode) (struct urb *urb, struct uvc_video_device *video,
			struct uvc_buffer *buf);

	/* Context data used by the bulk completion handler. */
	struct {
		__u8 header[256];
		unsigned int header_size;
		int skip_payload;
		__u32 payload_size;
		__u32 max_payload_size;
	} bulk;

	struct urb *urb[UVC_URBS];
	char *urb_buffer[UVC_URBS];
	dma_addr_t urb_dma[UVC_URBS];
	unsigned int urb_size;

	__u8 last_fid;
	__u16 wWidth;
};

enum uvc_device_state {
	UVC_DEV_DISCONNECTED = 1,
};

struct uvc_device {
	struct usb_device *udev;
	struct usb_interface *intf;
	unsigned long warnings;
	__u32 quirks;
	int intfnum;
	char name[32];

	enum uvc_device_state state;
	struct kref kref;
	struct list_head list;

	/* Video control interface */
	__u16 uvc_version;
	__u32 clock_frequency;

	struct list_head entities;

	struct uvc_video_device video;

	/* Status Interrupt Endpoint */
	struct usb_host_endpoint *int_ep;
	struct urb *int_urb;
	__u8 *status;
	struct input_dev *input;

	/* Video Streaming interfaces */
	struct list_head streaming;
	
	/* iP2970 motion flag */
	int motion;
};

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_v4l2.c

static int uvc_v4l2_set_format(struct uvc_video_device *video,
	struct v4l2_format *fmt)
{
	struct uvc_streaming_control probe;
	struct uvc_format *format;
	struct uvc_frame *frame;
	int ret;

	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	if (uvc_queue_streaming(&video->queue))
		return -EBUSY;

	ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
	if (ret < 0)
		return ret;

	if ((ret = uvc_commit_video(video, &probe)) < 0)
		return ret;

	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
	video->streaming->cur_format = format;
	video->streaming->cur_frame = frame;
	video->wWidth = frame->wWidth;

	return 0;
}

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_video.c

#define	USE_IP297X			1
#define	IP297X_MAX_PAYLOAD		956
#define IP297X_MOTION_FLAG_OFFSET	4

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_video.c

	ctrl->dwMaxPayloadTransferSize = IP297X_MAX_PAYLOAD;
//		le32_to_cpu(get_unaligned((__le32 *)&data[22]));

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_video.c

static int uvc_video_decode_start(struct uvc_video_device *video,
		struct uvc_buffer *buf, const __u8 *data, int len)
{
	__u8 fid;
	int  jpeg_head=0;
	static unsigned long uvc_sof_token_counter, uvc_sof_token_counter_prev;

	/* Sanity checks:
	 * - packet must be at least 2 bytes long
	 * - bHeaderLength value must be at least 2 bytes (see above)
	 * - bHeaderLength value can't be larger than the packet size.
	 */
	if (len < 2 || data[0] < 2 || data[0] > len)
		return -EINVAL;

	/* Skip payloads marked with the error bit ("error frames"). */
#if (USE_IP297X == 0)
	if (data[1] & UVC_STREAM_ERR) {
		uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
			  "set).\n");
		return -ENODATA;
	}
	fid = data[1] & UVC_STREAM_FID;
#endif

	/* Store the payload FID bit and return immediately when the buffer is
	 * NULL.
	 */
	if (buf == NULL) {
		video->last_fid = fid;
		return -ENODATA;
	}
#if (USE_IP297X == 1)
	if ( (len >= 14) && (data[12] == 0xff) && (data[13] == 0xd8) ) {
		jpeg_head = 1;
		if ( buf->buf.bytesused ) {
			buf->buf.bytesused = 0;
			buf->state = UVC_BUF_STATE_QUEUED;
		}	
	}
	if ( video->wWidth == 160 ) {	// QQVGA
		uvc_sof_token_counter = (data[11] << 8) + data[10];
		if ( ((uvc_sof_token_counter - 1 ) & 0x7ff ) != uvc_sof_token_counter_prev ) {
			if ( buf->buf.bytesused ) {
				buf->buf.bytesused = 0;
				buf->state = UVC_BUF_STATE_QUEUED;
			}	
		}
		uvc_sof_token_counter_prev = uvc_sof_token_counter;
	}
#endif
	/* Synchronize to the input stream by waiting for the FID bit to be
	 * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
	 * queue->last_fid is initialized to -1, so the first isochronous
	 * frame will always be in sync.
	 *
	 * If the device doesn't toggle the FID bit, invert video->last_fid
	 * when the EOF bit is set to force synchronisation on the next packet.
	 */
	if (buf->state != UVC_BUF_STATE_ACTIVE) {
#if (USE_IP297X == 1)
		if ( data[0] != 0x0c ) {
			printk("(drop header %d)", data[0]);
			return -ENODATA;
		}
		if ( (len >= 14) && (jpeg_head != 1) ) {
			return -ENODATA;
		}
#else		
		if (fid == video->last_fid) {
			uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
				"sync).\n");
			if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
			    (data[1] & UVC_STREAM_EOF))
				video->last_fid ^= UVC_STREAM_FID;
			return -ENODATA;
		}
#endif
		/* TODO: Handle PTS and SCR. */
		buf->state = UVC_BUF_STATE_ACTIVE;
	}

	/* Mark the buffer as done if we're at the beginning of a new frame.
	 * End of frame detection is better implemented by checking the EOF
	 * bit (FID bit toggling is delayed by one frame compared to the EOF
	 * bit), but some devices don't set the bit at end of frame (and the
	 * last payload can be lost anyway). We thus must check if the FID has
	 * been toggled.
	 *
	 * queue->last_fid is initialized to -1, so the first isochronous
	 * frame will never trigger an end of frame detection.
	 *
	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
	 * as it doesn't make sense to return an empty buffer. This also
	 * avoids detecting and of frame conditions at FID toggling if the
	 * previous payload had the EOF bit set.
	 */
#if  (USE_IP297X == 0)
	if (fid != video->last_fid && buf->buf.bytesused != 0) {
		uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
				"toggled).\n");
		buf->state = UVC_BUF_STATE_DONE;
		return -EAGAIN;
	}

	video->last_fid = fid;
#endif
	return data[0];
}

static void uvc_video_decode_data(struct uvc_video_device *video,
		struct uvc_buffer *buf, const __u8 *data, int len)
{
	struct uvc_video_queue *queue = &video->queue;
	unsigned int maxlen, nbytes;
	void *mem;

	if (len <= 0)
		return;

	/* Copy the video data to the buffer. */
	maxlen = buf->buf.length - buf->buf.bytesused;
	mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
	nbytes = min((unsigned int)len, maxlen);
	memcpy(mem, data, nbytes);
	buf->buf.bytesused += nbytes;

	/* Complete the current frame if the buffer size was exceeded. */
	if (len > maxlen) {
		uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
		buf->state = UVC_BUF_STATE_DONE;
	}
}

static void uvc_video_decode_end(struct uvc_video_device *video,
		struct uvc_buffer *buf, const __u8 *data, int len)
{
#if (USE_IP297X == 1)
	struct uvc_video_queue *queue = &video->queue;
	u8 *mem;

	if ( (data[len-2] == 0xff) && (data[len-1] == 0xd9) ) {
		buf->state = UVC_BUF_STATE_DONE;
		mem = (u8 *) (queue->mem + buf->buf.m.offset + IP297X_MOTION_FLAG_OFFSET);
		if ( video->dev->motion ) {
			video->dev->motion = 0;	/* clear iP2970 Motion detect */
			*mem |= 0x80;		/* set motion flag to 0xFFC0 length MSB */
		} else {
			*mem &= 0x7f;		/* clear motion flag to 0xFFC0 length MSB */
		}
	}
#else	
	/* Mark the buffer as done if the EOF marker is set. */
	if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
		uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
		if (data[0] == len)
			uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
		buf->state = UVC_BUF_STATE_DONE;
		if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
			video->last_fid ^= UVC_STREAM_FID;
	}
#endif
}

/* ------------------------------------------------------------------------
 * URB handling
 */

/*
 * Completion handler for video URBs.
 */
static void uvc_video_decode_isoc(struct urb *urb,
	struct uvc_video_device *video, struct uvc_buffer *buf)
{
	u8 *mem;
	int ret, i;

	for (i = 0; i < urb->number_of_packets; ++i) {
		if (urb->iso_frame_desc[i].status < 0) {
			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
				"lost (%d).\n", urb->iso_frame_desc[i].status);
			continue;
		}

		/* Decode the payload header. */
		mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
		do {
			ret = uvc_video_decode_start(video, buf, mem,
				urb->iso_frame_desc[i].actual_length);
			if (ret == -EAGAIN)
				buf = uvc_queue_next_buffer(&video->queue, buf);
		} while (ret == -EAGAIN);

		if (ret < 0)
			continue;

		/* Decode the payload data. */
		uvc_video_decode_data(video, buf, mem + ret,
			urb->iso_frame_desc[i].actual_length - ret);

		/* Process the header again. */
		uvc_video_decode_end(video, buf, mem,
			urb->iso_frame_desc[i].actual_length);

		if (buf->state == UVC_BUF_STATE_DONE ||
		    buf->state == UVC_BUF_STATE_ERROR)
			buf = uvc_queue_next_buffer(&video->queue, buf);
	}
}

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_status.c

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static void uvc_status_complete(struct urb *urb, struct pt_regs *regs)
#else
static void uvc_status_complete(struct urb *urb)
#endif
{
	struct uvc_device *dev = urb->context;
	int len, ret;

	switch (urb->status) {
	case 0:
		break;

	case -ENOENT:		/* usb_kill_urb() called. */
	case -ECONNRESET:	/* usb_unlink_urb() called. */
	case -ESHUTDOWN:	/* The endpoint is being disabled. */
	case -EPROTO:		/* Device is disconnected (reported by some
				 * host controller). */
		return;

	default:
		uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
			"completion handler.\n", urb->status);
		return;
	}

	len = urb->actual_length;
	if (len > 0) {
		switch (dev->status[0] & 0x0f) {
		case UVC_STATUS_TYPE_CONTROL:
			uvc_event_control(dev, dev->status, len);
			dev->motion = 1;
			break;

		case UVC_STATUS_TYPE_STREAMING:
			uvc_event_streaming(dev, dev->status, len);
			break;

		default:
#if 0
			uvc_printk(KERN_INFO, "unknown event type %u.\n",
				dev->status[0]);
#endif
			break;
		}
	}

	/* Resubmit the URB. */
	urb->interval = dev->int_ep->desc.bInterval;
	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
		uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
			ret);
	}
}

int uvc_status_init(struct uvc_device *dev)
{
	struct usb_host_endpoint *ep = dev->int_ep;
	unsigned int pipe;
	int interval;

	if (ep == NULL)
		return 0;

	uvc_input_init(dev);

	dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
	if (dev->status == NULL)
		return -ENOMEM;

	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (dev->int_urb == NULL) {
		kfree(dev->status);
		return -ENOMEM;
	}

	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
	dev->motion = 0;

	/* For high-speed interrupt endpoints, the bInterval value is used as
	 * an exponent of two. Some developers forgot about it.
	 */
	interval = ep->desc.bInterval;
	if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
	    (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
		interval = fls(interval) - 1;

	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
		dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
		dev, interval);

	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
}

============================================================================
/linux-2.6.21.x/drivers/media/video/uvc/uvc_driver.c

	/* SiGma Micro USB Web Camera */
	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
				| USB_DEVICE_ID_MATCH_INT_INFO,
	  .idVendor		= 0x1c4f,
	  .idProduct		= 0x3000,
	  .bInterfaceClass	= USB_CLASS_VIDEO,
	  .bInterfaceSubClass	= 1,
	  .bInterfaceProtocol	= 0,
	  .driver_info		= UVC_QUIRK_PROBE_MINMAX
				| UVC_QUIRK_IGNORE_SELECTOR_UNIT},
	/* iPassion iP2970 */
	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
				| USB_DEVICE_ID_MATCH_INT_INFO,
	  .idVendor		= 0x1B3B,
	  .idProduct		= 0x2970,
	  .bInterfaceClass	= USB_CLASS_VIDEO,
	  .bInterfaceSubClass	= 1,
	  .bInterfaceProtocol	= 0,
	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
	/* Generic USB Video Class */

============================================================================
/linux-2.6.21.x/drivers/usb/dwc_otg/dwc_otg_icd_intr.c

static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *hcd,
				      dwc_hc_t *hc,
				      dwc_otg_hc_regs_t *hc_regs,
				      dwc_otg_qtd_t *qtd)
{
	hcint_data_t hcint;
	hcintmsk_data_t hcintmsk;
	int out_nak_enh = 0;

	/* For core with OUT NAK enhancement, the flow for high-
	 * speed CONTROL/BULK OUT is handled a little differently.
	 */
	if (hcd->core_if->snpsid >= 0x4F54271A) {
		if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
		    (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
		     hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
			printk(KERN_DEBUG "OUT NAK enhancement enabled\n");
			out_nak_enh = 1;
		} else {
			printk(KERN_DEBUG "OUT NAK enhancement disabled, not HS Ctrl/Bulk OUT EP\n");
		}
#if 0
	} else {
		printk(KERN_DEBUG "OUT NAK enhancement disabled, no core support\n");
#endif
	}

	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
	    hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
		/*
		 * Just release the channel. A dequeue can happen on a
		 * transfer timeout. In the case of an AHB Error, the channel
		 * was forced to halt because there's no way to gracefully
		 * recover.
		 */
		release_channel(hcd, hc, qtd, hc->halt_status);
		return;
	}
