V4L/DVB (12799): tm6000: avoid troubles if a header is broken on separate URBs
authorMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 19 Sep 2007 19:24:05 +0000 (16:24 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 18 May 2010 03:39:44 +0000 (00:39 -0300)
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/staging/tm6000/tm6000-usb-isoc.h
drivers/staging/tm6000/tm6000-video.c

index 27b103f939d9b00f055e5d9e791ab8af485ade4f..83a4ed0d1bca25f665b69c8d235da93391b2a07c 100644 (file)
@@ -38,4 +38,7 @@ struct usb_isoc_ctl {
 
                /* Last field: ODD or EVEN? */
        int                             field;
+
+       u32                             tmp_buf;
+       int                             tmp_buf_len;
 };
index 44d455f2d3150dd22588559814ed8b386dea2ea0..372850c3e70b646bfbe7ec4ef3b0311e7827c5ed 100644 (file)
@@ -212,7 +212,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;
 
@@ -220,8 +220,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)
@@ -232,6 +231,7 @@ static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
                                " line=%d, field=%d\n",
                                size, block, line, field);
 
+
                pktsize = TM6000_URB_MSG_LEN;
 /////////////////////////////
 /// nao seria size???
@@ -251,8 +251,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) {
@@ -278,26 +279,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);
        }
@@ -581,7 +610,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;
                }