/*
 * Start the transfer of a D channel frame.
 */
static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
{
	struct st5481_d_out *d_out = &adapter->d_out;
	struct urb *urb;
	unsigned int num_packets, packet_offset;
	int len, buf_size, bytes_sent;
	struct sk_buff *skb;
	struct iso_packet_descriptor *desc;

	if (d_out->fsm.state != ST_DOUT_NORMAL)
		return;

	if (test_and_set_bit(buf_nr, &d_out->busy)) {
		DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
		return;
	}
	urb = d_out->urb[buf_nr];

	skb = d_out->tx_skb;

	buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
	
	if (skb) {
		len = isdnhdlc_encode(&d_out->hdlc_state,
				      skb->data, skb->len, &bytes_sent,
				      urb->transfer_buffer, buf_size);
		skb_pull(skb,bytes_sent);
	} else {
		// Send flags or idle
		len = isdnhdlc_encode(&d_out->hdlc_state,
				      NULL, 0, &bytes_sent,
				      urb->transfer_buffer, buf_size);
	}
	
	if (len < buf_size) {
		FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
	}
	if (skb && !skb->len) {
		d_out->tx_skb = NULL;
		D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
		dev_kfree_skb_any(skb);
	}

	// Prepare the URB
	urb->transfer_buffer_length = len;
	num_packets = 0;
	packet_offset = 0;
	while (packet_offset < len) {
		desc = &urb->iso_frame_desc[num_packets];
		desc->offset = packet_offset;
		desc->length = SIZE_ISO_PACKETS_D_OUT;
		if (len - packet_offset < desc->length)
			desc->length = len - packet_offset;
		num_packets++;
		packet_offset += desc->length;
	}
	urb->number_of_packets = num_packets;

	// Prepare the URB
	urb->dev = adapter->usb_dev;
	// Need to transmit the next buffer 2ms after the DEN_EVENT
	urb->transfer_flags = 0;
	urb->start_frame = usb_get_current_frame_number(adapter->usb_dev)+2;

	DBG_ISO_PACKET(0x20,urb);

	if (usb_submit_urb(urb) < 0) {
		// There is another URB queued up
		urb->transfer_flags = USB_ISO_ASAP;
		SUBMIT_URB(urb);
	}	
}
Example #2
0
usb_frame_number_t
usba10_usb_get_current_frame_number(dev_info_t	*dip)
{
	return (usb_get_current_frame_number(dip));
}
Example #3
0
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
		       const __u8 *data, int len)
{
	struct uvc_clock_sample *sample;
	unsigned int header_size;
	bool has_pts = false;
	bool has_scr = false;
	unsigned long flags;
	struct timespec ts;
	u16 host_sof;
	u16 dev_sof;

	switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
	case UVC_STREAM_PTS | UVC_STREAM_SCR:
		header_size = 12;
		has_pts = true;
		has_scr = true;
		break;
	case UVC_STREAM_PTS:
		header_size = 6;
		has_pts = true;
		break;
	case UVC_STREAM_SCR:
		header_size = 8;
		has_scr = true;
		break;
	default:
		header_size = 2;
		break;
	}

	/* Check for invalid headers. */
	if (len < header_size)
		return;

	/* Extract the timestamps:
	 *
	 * - store the frame PTS in the buffer structure
	 * - if the SCR field is present, retrieve the host SOF counter and
	 *   kernel timestamps and store them with the SCR STC and SOF fields
	 *   in the ring buffer
	 */
	if (has_pts && buf != NULL)
		buf->pts = get_unaligned_le32(&data[2]);

	if (!has_scr)
		return;

	/* To limit the amount of data, drop SCRs with an SOF identical to the
	 * previous one.
	 */
	dev_sof = get_unaligned_le16(&data[header_size - 2]);
	if (dev_sof == stream->clock.last_sof)
		return;

	stream->clock.last_sof = dev_sof;

	host_sof = usb_get_current_frame_number(stream->dev->udev);
	uvc_video_get_ts(&ts);

	/* The UVC specification allows device implementations that can't obtain
	 * the USB frame number to keep their own frame counters as long as they
	 * match the size and frequency of the frame number associated with USB
	 * SOF tokens. The SOF values sent by such devices differ from the USB
	 * SOF tokens by a fixed offset that needs to be estimated and accounted
	 * for to make timestamp recovery as accurate as possible.
	 *
	 * The offset is estimated the first time a device SOF value is received
	 * as the difference between the host and device SOF values. As the two
	 * SOF values can differ slightly due to transmission delays, consider
	 * that the offset is null if the difference is not higher than 10 ms
	 * (negative differences can not happen and are thus considered as an
	 * offset). The video commit control wDelay field should be used to
	 * compute a dynamic threshold instead of using a fixed 10 ms value, but
	 * devices don't report reliable wDelay values.
	 *
	 * See uvc_video_clock_host_sof() for an explanation regarding why only
	 * the 8 LSBs of the delta are kept.
	 */
	if (stream->clock.sof_offset == (u16)-1) {
		u16 delta_sof = (host_sof - dev_sof) & 255;
		if (delta_sof >= 10)
			stream->clock.sof_offset = delta_sof;
		else
			stream->clock.sof_offset = 0;
	}

	dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;

	spin_lock_irqsave(&stream->clock.lock, flags);

	sample = &stream->clock.samples[stream->clock.head];
	sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
	sample->dev_sof = dev_sof;
	sample->host_sof = host_sof;
	sample->host_ts = ts;

	/* Update the sliding window head and count. */
	stream->clock.head = (stream->clock.head + 1) % stream->clock.size;

	if (stream->clock.count < stream->clock.size)
		stream->clock.count++;

	spin_unlock_irqrestore(&stream->clock.lock, flags);
}