From 6eb5c8a6c82d7c753ea52df94ea2ff096b5aba96 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 8 Jan 2008 11:25:57 -0300 Subject: [PATCH] V4L/DVB (12823): tm6000: Uses another method for handling incomplete packets This requires a little more memory, and some memcpy to work, but the logic is simpler than the previous method. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-regs.h | 1 - drivers/staging/tm6000/tm6000-usb-isoc.h | 12 +- drivers/staging/tm6000/tm6000-video.c | 249 +++++++++++------------ 3 files changed, 129 insertions(+), 133 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h index 3d676fcc262d..85acc07f62e9 100644 --- a/drivers/staging/tm6000/tm6000-regs.h +++ b/drivers/staging/tm6000/tm6000-regs.h @@ -77,7 +77,6 @@ * Define TV Master TM5600/TM6000 URB message codes and length */ -#define TM6000_URB_MSG_LEN 180 enum { TM6000_URB_MSG_VIDEO=1, TM6000_URB_MSG_AUDIO, diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h index 42de91715185..10e72c04f74f 100644 --- a/drivers/staging/tm6000/tm6000-usb-isoc.h +++ b/drivers/staging/tm6000/tm6000-usb-isoc.h @@ -19,6 +19,8 @@ #include +#define TM6000_URB_MSG_LEN 180 + struct usb_isoc_ctl { /* max packet size of isoc transaction */ int max_pkt_size; @@ -32,16 +34,16 @@ struct usb_isoc_ctl { /* transfer buffers for isoc transfer */ char **transfer_buffer; - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; + /* Last buffer control */ + int pending; + int pos; /* Last field: ODD or EVEN? */ int field; /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; + u8 tbuf[TM6000_URB_MSG_LEN+4]; + size_t len; /* Stores already requested buffers */ struct tm6000_buffer *buf; diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 107d597038b8..b72cfd0d7559 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -215,92 +215,83 @@ static int copy_packet (struct urb *urb, u32 header, u8 **ptr, u8 *endp, */ unsigned int linewidth=(*buf)->vb.width<<1; + c=(header>>24) & 0xff; + + /* split the header fields */ + size = (((header & 0x7e)<<1) -1) *4; + block = (header>>7) & 0xf; + field = (header>>11) & 0x1; + line = (header>>12) & 0x1ff; + cmd = (header>>21) & 0x7; + + /* Validates header fields */ + if(size>TM6000_URB_MSG_LEN) + size = TM6000_URB_MSG_LEN; + + if (cmd == TM6000_URB_MSG_VIDEO) { + if ((block+1)*TM6000_URB_MSG_LEN>linewidth) + cmd = TM6000_URB_MSG_ERR; + + /* FIXME: Mounts the image as field0+field1 + * It should, instead, check if the user selected + * entrelaced or non-entrelaced mode + */ + pos= ((line<<1)+field)*linewidth + + block*TM6000_URB_MSG_LEN; + + /* Don't allow to write out of the buffer */ + if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) { + dprintk(dev, V4L2_DEBUG_ISOC, + "ERR: size=%d, num=%d, line=%d, " + "field=%d\n", + size, block, line, field); - if (!dev->isoc_ctl.cmd) { - c=(header>>24) & 0xff; - - /* split the header fields */ - size = (((header & 0x7e)<<1) -1) *4; - block = (header>>7) & 0xf; - field = (header>>11) & 0x1; - line = (header>>12) & 0x1ff; - cmd = (header>>21) & 0x7; + cmd = TM6000_URB_MSG_ERR; + } + } else { + pos=0; + } - /* Validates header fields */ - if(size>TM6000_URB_MSG_LEN) - size = TM6000_URB_MSG_LEN; + /* Prints debug info */ + dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, " + " line=%d, field=%d\n", + size, block, line, field); + + if ((last_line!=line)&&(last_line+1!=line) && + (cmd != TM6000_URB_MSG_ERR) ) { + if (cmd != TM6000_URB_MSG_VIDEO) { + dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, " + "size=%d, num=%d, line=%d, field=%d\n", + cmd, size, block, line, field); + } + if (start_line<0) + start_line=last_line; + /* Prints debug info */ + dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, " + "field=%d\n", + start_line, last_line, field); - if (cmd == TM6000_URB_MSG_VIDEO) { - if ((block+1)*TM6000_URB_MSG_LEN>linewidth) - cmd = TM6000_URB_MSG_ERR; + if ((start_line<6 && last_line>200) && + (last_field != field) ) { - /* FIXME: Mounts the image as field0+field1 - * It should, instead, check if the user selected - * entrelaced or non-entrelaced mode - */ - pos= ((line<<1)+field)*linewidth + - block*TM6000_URB_MSG_LEN; + dev->isoc_ctl.nfields++; + if (dev->isoc_ctl.nfields>=2) { + dev->isoc_ctl.nfields=0; - /* Don't allow to write out of the buffer */ - if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) { + /* Announces that a new buffer were filled */ + buffer_filled (dev, dma_q, *buf); dprintk(dev, V4L2_DEBUG_ISOC, - "ERR: size=%d, num=%d, line=%d, " - "field=%d\n", - size, block, line, field); - - cmd = TM6000_URB_MSG_ERR; - } - } else { - pos=0; - } - - /* Prints debug info */ - dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, " - " line=%d, field=%d\n", - size, block, line, field); - - if ((last_line!=line)&&(last_line+1!=line) && - (cmd != TM6000_URB_MSG_ERR) ) { - if (cmd != TM6000_URB_MSG_VIDEO) { - dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, " - "size=%d, num=%d, line=%d, field=%d\n", - cmd, size, block, line, field); - } - if (start_line<0) - start_line=last_line; - /* Prints debug info */ - dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, " - "field=%d\n", - start_line, last_line, field); - - if ((start_line<6 && last_line>200) && - (last_field != field) ) { - - dev->isoc_ctl.nfields++; - 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); - } + "new buffer filled\n"); + rc=get_next_buf (dma_q, buf); } - - start_line=line; - last_field=field; } - 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; + start_line=line; + last_field=field; } + last_line=line; + + pktsize = TM6000_URB_MSG_LEN; cpysize=(endp-(*ptr)>size)?size:endp-(*ptr); @@ -325,19 +316,7 @@ printk ("%ld: cmd=%s, size=%d\n", jiffies, tm6000_msg_type[cmd],size); } } - if (cpysizeisoc_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; - } + (*ptr)+=cpysize; return rc; } @@ -347,57 +326,73 @@ 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=data, *endp=data+len; + u8 *ptr, *endp; unsigned long header=0; - int rc=0; + int rc=0, size; - for (ptr=data; ptrisoc_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; - } - 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; - } - } + /* 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); + + /* 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) + 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; + } + 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 (ptrisoc_ctl.pending) { /* Seek for sync */ for (;ptrTM6000_URB_MSG_LEN) + size = TM6000_URB_MSG_LEN; + + if (ptr+3+size >= endp) { + int len = endp - ptr; - 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; + memcpy (dev->isoc_ctl.tbuf, ptr, len); + dev->isoc_ctl.len = len; + dev->isoc_ctl.pending = 1; 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); + rc=copy_packet(urb, header, &ptr, endp, out_p, buf); if (rc<0) { buf=NULL; printk(KERN_ERR "tm6000: buffer underrun at %ld\n", -- 2.30.2