Commit ed0236af authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

V4L/DVB (12836): tm6000: revert to an old way to copy video



The new way is causing machine hangups. This one works.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c144c037
Loading
Loading
Loading
Loading
+5 −9
Original line number Diff line number Diff line
@@ -34,24 +34,20 @@ struct usb_isoc_ctl {
		/* transfer buffers for isoc transfer */
	char				**transfer_buffer;

		/* Last buffer control */
	int				pending;
	int				pos;
		/* Last buffer command and region */
	u8				cmd;
	int				pos, size, pktsize;

		/* Last field: ODD or EVEN? */
	int				field;

		/* Stores incomplete commands */
	u8				tbuf[TM6000_URB_MSG_LEN+4];
	size_t				len;
	u32				tmp_buf;
	int				tmp_buf_len;

		/* Stores already requested buffers */
	struct tm6000_buffer    	*buf;

		/* Stores the number of received fields */
	int				nfields;

		/* Checks if a complete field were received */
	int				last_line;
	unsigned int			fields:2;
};
+191 −196
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
	 */
	unsigned int linewidth = (*buf)->vb.width << 1;

	if (!dev->isoc_ctl.cmd) {
		c = (header >> 24) & 0xff;

		/* split the header fields */
@@ -234,22 +235,6 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
				" line=%d, field=%d\n",
				size, block, line, field);

	/* Checks if a complete set of frame0 + frame 1 were received */
	if (dev->isoc_ctl.last_line > line) {
		if (dev->isoc_ctl.fields == 3) {
			/* Announces that a new buffer were filled */
			buffer_filled(dev, dma_q, *buf);
			dprintk(dev, V4L2_DEBUG_ISOC,
					"new buffer filled\n");
			rc = get_next_buf(dma_q, buf);

			dev->isoc_ctl.fields = 0;
		} else {
			dev->isoc_ctl.fields |= 1 << field;
		}
	}
	dev->isoc_ctl.last_line = line;

		if ((last_line!=line)&&(last_line+1!=line) &&
		    (cmd != TM6000_URB_MSG_ERR) )  {
			if (cmd != TM6000_URB_MSG_VIDEO)  {
@@ -268,8 +253,15 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
				(last_field != field) ) {

				dev->isoc_ctl.nfields++;
			if (dev->isoc_ctl.nfields >= 2)
				if (dev->isoc_ctl.nfields>=2) {
					dev->isoc_ctl.nfields=0;

					/* Announces that a new buffer were filled */
					buffer_filled (dev, dma_q, *buf);
					dprintk(dev, V4L2_DEBUG_ISOC,
							"new buffer filled\n");
					rc=get_next_buf (dma_q, buf);
				}
			}

			start_line=line;
@@ -278,6 +270,13 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
		last_line=line;

		pktsize = TM6000_URB_MSG_LEN;
	} else {
		/* Continue the last copy */
		cmd = dev->isoc_ctl.cmd;
		size= dev->isoc_ctl.size;
		pos = dev->isoc_ctl.pos;
		pktsize = dev->isoc_ctl.pktsize;
	}

	cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;

@@ -286,15 +285,13 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
		switch(cmd) {
		case TM6000_URB_MSG_VIDEO:
			/* Fills video buffer */
			if (__copy_to_user(&out_p[pos], *ptr, cpysize) != 0)
				tm6000_err("copy_to_user failed.\n");

			memcpy(&out_p[pos], *ptr, cpysize);
			break;
		case TM6000_URB_MSG_PTS:
			break;
		case TM6000_URB_MSG_AUDIO:
/* Need some code to process audio */
			printk(KERN_INFO "%ld: cmd=%s, size=%d\n", jiffies,
printk ("%ld: cmd=%s, size=%d\n", jiffies,
				tm6000_msg_type[cmd],size);
			break;
		default:
@@ -302,7 +299,19 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
						tm6000_msg_type[cmd],size);
		}
	}
	if (cpysize<size) {
		/* End of URB packet, but cmd processing is not
		 * complete. Preserve the state for a next packet
		 */
		dev->isoc_ctl.pos = pos+cpysize;
		dev->isoc_ctl.size= size-cpysize;
		dev->isoc_ctl.cmd = cmd;
		dev->isoc_ctl.pktsize = pktsize-cpysize;
		(*ptr)+=cpysize;
	} else {
		dev->isoc_ctl.cmd = 0;
		(*ptr)+=pktsize;
	}

	return rc;
}
@@ -312,71 +321,55 @@ static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	u8 *ptr, *endp;
	u8 *ptr=data, *endp=data+len;
	unsigned long header=0;
	int rc = 0, size;

	/* Process pending data */
	if (dev->isoc_ctl.pending) {
		memcpy(dev->isoc_ctl.tbuf + dev->isoc_ctl.len, ptr,
		       sizeof(dev->isoc_ctl.tbuf) - dev->isoc_ctl.len);
	int rc=0;

		/* Seek for sync */
		endp = dev->isoc_ctl.tbuf + sizeof(dev->isoc_ctl.tbuf);
		for (ptr = dev->isoc_ctl.tbuf; ptr < endp - 3; ptr++) {
			if (*(ptr + 3) == 0x47)
	for (ptr=data; ptr<endp;) {
		if (!dev->isoc_ctl.cmd) {
			u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
			/* FIXME: This seems very complex
			 * It just recovers up to 3 bytes of the header that
			 * might be at the previous packet
			 */
			if (dev->isoc_ctl.tmp_buf_len) {
				while (dev->isoc_ctl.tmp_buf_len) {
					if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
						break;
					}
		header = *(unsigned long *)ptr;
		size   = (((header & 0x7e) << 1) - 1) * 4;
		if (size > TM6000_URB_MSG_LEN)
			size = TM6000_URB_MSG_LEN;

		if (ptr + 3 + size >= endp) {
			printk(KERN_ERR "tm6000: broken data\n");
			ptr = data;
			goto process_new_uri;
					p++;
					dev->isoc_ctl.tmp_buf_len--;
				}
				if (dev->isoc_ctl.tmp_buf_len) {
					memcpy (&header,p,
						dev->isoc_ctl.tmp_buf_len);
					memcpy (((u8 *)header)+
						dev->isoc_ctl.tmp_buf,
						ptr,
						4-dev->isoc_ctl.tmp_buf_len);
					ptr+=4-dev->isoc_ctl.tmp_buf_len;
					goto HEADER;
				}
		ptr += 4;

		/* Copy or continue last copy */
		rc = copy_packet(urb, header, &ptr, endp, out_p, buf);
		if (rc < 0) {
			buf = NULL;
			printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
					jiffies);
			return rc;
			}
		dev->isoc_ctl.pending = 0;
		ptr = data + (ptr - dev->isoc_ctl.tbuf);
	} else
		ptr = data;

process_new_uri:
	endp = data + len;
	while (ptr < endp) {
		if (!dev->isoc_ctl.pending) {
			/* Seek for sync */
			for (;ptr<endp-3;ptr++) {
				if (*(ptr+3)==0x47)
					break;
			}
			header = *(unsigned long *)ptr;
			size   = (((header & 0x7e) << 1) - 1) * 4;
			if (size > TM6000_URB_MSG_LEN)
				size = TM6000_URB_MSG_LEN;

			if (ptr + 3 + size >= endp) {
				int len = endp - ptr;

				memcpy(dev->isoc_ctl.tbuf, ptr, len);
				dev->isoc_ctl.len = len;
				dev->isoc_ctl.pending = 1;
			if (ptr+3>=endp) {
				dev->isoc_ctl.tmp_buf_len=endp-ptr;
				memcpy (&dev->isoc_ctl.tmp_buf,ptr,
					dev->isoc_ctl.tmp_buf_len);
				dev->isoc_ctl.cmd=0;
				return rc;
			}

			/* Get message header */
			header=*(unsigned long *)ptr;
			ptr+=4;
		}

HEADER:
		/* Copy or continue last copy */
		rc=copy_packet(urb,header,&ptr,endp,out_p,buf);
		if (rc<0) {
@@ -402,10 +395,8 @@ static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,

	while (len>0) {
		cpysize=min(len,(*buf)->vb.size-pos);

		if (__copy_to_user(&out_p[pos], ptr, cpysize) != 0)
			tm6000_err("copy_to_user failed.\n");

//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
		memcpy(&out_p[pos], ptr, cpysize);
		pos+=cpysize;
		ptr+=cpysize;
		len-=cpysize;
@@ -426,7 +417,7 @@ static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
	return rc;
}

static inline void print_err_status(struct tm6000_core *dev,
static void inline print_err_status (struct tm6000_core *dev,
				     int packet, int status)
{
	char *errmsg = "Unknown";
@@ -461,8 +452,7 @@ static inline void print_err_status(struct tm6000_core *dev,
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
			status, errmsg);
	} else {
		dprintk(dev, V4L2_DEBUG_QUEUE,
			"URB packet %d, status %d [%s].\n",
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
			packet, status, errmsg);
	}
}
@@ -479,7 +469,9 @@ static inline int tm6000_isoc_copy(struct urb *urb, struct tm6000_buffer **buf)
	int i, len=0, rc=1;
	int size=(*buf)->vb.size;
	char *p;
	unsigned long copied = 0;
	unsigned long copied;

	copied=0;

	if (urb->status<0) {
		print_err_status (dev,-1,urb->status);
@@ -496,18 +488,21 @@ static inline int tm6000_isoc_copy(struct urb *urb, struct tm6000_buffer **buf)

		len=urb->iso_frame_desc[i].actual_length;

//		if (len>=TM6000_URB_MSG_LEN) {
			p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
			if (!urb->iso_frame_desc[i].status) {
				if (((*buf)->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
					rc=copy_multiplexed(p,outp,len,urb,buf);
					if (rc<=0)
						return rc;
			} else
				} else {
					copy_streams(p,outp,len,urb,buf);
				}
			}
			copied += len;
			if (copied>=size)
				break;
//		}
	}
	return rc;
}