summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2007-09-19 16:24:05 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2007-09-19 16:24:05 -0300
commit36ada11670cb87430951f76d571fdf37f08432bf (patch)
tree6111bd4da78cc63dc4200cf41133b6aa535d78dc
parent631a2a6aa106d15af6c8fe401d654d2da0c4bdac (diff)
downloadmediapointer-dvb-s2-36ada11670cb87430951f76d571fdf37f08432bf.tar.gz
mediapointer-dvb-s2-36ada11670cb87430951f76d571fdf37f08432bf.tar.bz2
tm6000: avoid troubles if a header is broken on two separate URBs
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--linux/drivers/staging/tm6000/tm6000-usb-isoc.h3
-rw-r--r--linux/drivers/staging/tm6000/tm6000-video.c80
2 files changed, 55 insertions, 28 deletions
diff --git a/linux/drivers/staging/tm6000/tm6000-usb-isoc.h b/linux/drivers/staging/tm6000/tm6000-usb-isoc.h
index c712b9567..226cc7273 100644
--- a/linux/drivers/staging/tm6000/tm6000-usb-isoc.h
+++ b/linux/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -39,4 +39,7 @@ struct usb_isoc_ctl {
/* Last field: ODD or EVEN? */
int field;
+
+ u32 tmp_buf;
+ int tmp_buf_len;
};
diff --git a/linux/drivers/staging/tm6000/tm6000-video.c b/linux/drivers/staging/tm6000/tm6000-video.c
index 22a670789..d24c585ba 100644
--- a/linux/drivers/staging/tm6000/tm6000-video.c
+++ b/linux/drivers/staging/tm6000/tm6000-video.c
@@ -217,7 +217,7 @@ static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
/* Validates header fields */
if(size>TM6000_URB_MSG_LEN)
- size=TM6000_URB_MSG_LEN;
+ size = TM6000_URB_MSG_LEN;
if(block>=8)
cmd = TM6000_URB_MSG_ERR;
@@ -225,8 +225,7 @@ static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
* It should, instead, check if the user selected
* entrelaced or non-entrelaced mode
*/
- pos=((line<<1)+field)*linesize+
- block*TM6000_URB_MSG_LEN;
+ pos=((line<<1)+field)*linesize+block*TM6000_URB_MSG_LEN;
/* Don't allow to write out of the buffer */
if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size)
@@ -247,24 +246,19 @@ static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
}
#endif
#if 0
- if (dev->isoc_ctl.field != field) {
- dev->isoc_ctl.field = field;
+ if (dev->isoc_ctl.field != field) {
+ dev->isoc_ctl.field = field;
- /* Announces that a new buffer were filled */
- buffer_filled (dev, *buf);
- dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
+ /* Announces that a new buffer were filled */
+ buffer_filled (dev, *buf);
+ dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
- rc=get_next_buf (dma_q, buf);
- if (rc<0)
- *buf=NULL;
- }
-#endif
-#if 0
- dev->isoc_ctl.cmd = cmd;
- dev->isoc_ctl.size = size;
- dev->isoc_ctl.pos = pos;
- dev->isoc_ctl.pktsize = pktsize;
+ rc=get_next_buf (dma_q, buf);
+ if (rc<0)
+ *buf=NULL;
+ }
#endif
+
pktsize = TM6000_URB_MSG_LEN;
/////////////////////////////
/// nao seria size???
@@ -292,8 +286,9 @@ static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
switch(cmd) {
case TM6000_URB_MSG_VIDEO:
/* Fills video buffer */
- bufcpy(*buf,&out_p[pos],ptr,cpysize);
- break;
+ if (__copy_to_user(&out_p[pos],ptr,cpysize)!=0)
+ tm6000_err("copy_to_user failed.\n");
+ break;
}
}
if (cpysize<size) {
@@ -319,26 +314,54 @@ 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;
- u32 header=0;
+ unsigned long header=0;
int rc=0;
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;
+ }
+ 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;
+ }
+ }
/* Seek for sync */
- for (ptr+=3;ptr<endp;ptr++) {
- if (*ptr==0x47) {
- ptr-=3;
+ for (;ptr<endp-3;ptr++) {
+ if (*(ptr+3)==0x47)
break;
- }
}
- if (ptr>=endp)
+
+ 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 */
ptr=copy_packet(urb,header,ptr,endp,out_p,buf);
}
@@ -631,7 +654,8 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev,
sb_size, GFP_KERNEL, &urb->transfer_dma);
if (!dev->isoc_ctl.transfer_buffer[i]) {
tm6000_err ("unable to allocate %i bytes for transfer"
- " buffer %i\n", sb_size, i);
+ " buffer %i, in int=%i\n",
+ sb_size, i, in_interrupt());
tm6000_uninit_isoc(dev);
return -ENOMEM;
}