aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-01-08 09:25:57 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-17 23:40:05 -0400
commit6eb5c8a6c82d7c753ea52df94ea2ff096b5aba96 (patch)
tree12d4a98f98b18e1700479b656fdce97ac83643b5 /drivers
parent29c389be1ceb714739cdcd41fec6547d19b32864 (diff)
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 <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/tm6000/tm6000-regs.h1
-rw-r--r--drivers/staging/tm6000/tm6000-usb-isoc.h12
-rw-r--r--drivers/staging/tm6000/tm6000-video.c249
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 @@
77 * Define TV Master TM5600/TM6000 URB message codes and length 77 * Define TV Master TM5600/TM6000 URB message codes and length
78 */ 78 */
79 79
80#define TM6000_URB_MSG_LEN 180
81enum { 80enum {
82 TM6000_URB_MSG_VIDEO=1, 81 TM6000_URB_MSG_VIDEO=1,
83 TM6000_URB_MSG_AUDIO, 82 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 @@
19 19
20#include <linux/videodev2.h> 20#include <linux/videodev2.h>
21 21
22#define TM6000_URB_MSG_LEN 180
23
22struct usb_isoc_ctl { 24struct usb_isoc_ctl {
23 /* max packet size of isoc transaction */ 25 /* max packet size of isoc transaction */
24 int max_pkt_size; 26 int max_pkt_size;
@@ -32,16 +34,16 @@ struct usb_isoc_ctl {
32 /* transfer buffers for isoc transfer */ 34 /* transfer buffers for isoc transfer */
33 char **transfer_buffer; 35 char **transfer_buffer;
34 36
35 /* Last buffer command and region */ 37 /* Last buffer control */
36 u8 cmd; 38 int pending;
37 int pos, size, pktsize; 39 int pos;
38 40
39 /* Last field: ODD or EVEN? */ 41 /* Last field: ODD or EVEN? */
40 int field; 42 int field;
41 43
42 /* Stores incomplete commands */ 44 /* Stores incomplete commands */
43 u32 tmp_buf; 45 u8 tbuf[TM6000_URB_MSG_LEN+4];
44 int tmp_buf_len; 46 size_t len;
45 47
46 /* Stores already requested buffers */ 48 /* Stores already requested buffers */
47 struct tm6000_buffer *buf; 49 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,
215 */ 215 */
216 unsigned int linewidth=(*buf)->vb.width<<1; 216 unsigned int linewidth=(*buf)->vb.width<<1;
217 217
218 c=(header>>24) & 0xff;
219
220 /* split the header fields */
221 size = (((header & 0x7e)<<1) -1) *4;
222 block = (header>>7) & 0xf;
223 field = (header>>11) & 0x1;
224 line = (header>>12) & 0x1ff;
225 cmd = (header>>21) & 0x7;
226
227 /* Validates header fields */
228 if(size>TM6000_URB_MSG_LEN)
229 size = TM6000_URB_MSG_LEN;
230
231 if (cmd == TM6000_URB_MSG_VIDEO) {
232 if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
233 cmd = TM6000_URB_MSG_ERR;
234
235 /* FIXME: Mounts the image as field0+field1
236 * It should, instead, check if the user selected
237 * entrelaced or non-entrelaced mode
238 */
239 pos= ((line<<1)+field)*linewidth +
240 block*TM6000_URB_MSG_LEN;
241
242 /* Don't allow to write out of the buffer */
243 if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
244 dprintk(dev, V4L2_DEBUG_ISOC,
245 "ERR: size=%d, num=%d, line=%d, "
246 "field=%d\n",
247 size, block, line, field);
218 248
219 if (!dev->isoc_ctl.cmd) { 249 cmd = TM6000_URB_MSG_ERR;
220 c=(header>>24) & 0xff; 250 }
221 251 } else {
222 /* split the header fields */ 252 pos=0;
223 size = (((header & 0x7e)<<1) -1) *4; 253 }
224 block = (header>>7) & 0xf;
225 field = (header>>11) & 0x1;
226 line = (header>>12) & 0x1ff;
227 cmd = (header>>21) & 0x7;
228 254
229 /* Validates header fields */ 255 /* Prints debug info */
230 if(size>TM6000_URB_MSG_LEN) 256 dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
231 size = TM6000_URB_MSG_LEN; 257 " line=%d, field=%d\n",
258 size, block, line, field);
259
260 if ((last_line!=line)&&(last_line+1!=line) &&
261 (cmd != TM6000_URB_MSG_ERR) ) {
262 if (cmd != TM6000_URB_MSG_VIDEO) {
263 dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, "
264 "size=%d, num=%d, line=%d, field=%d\n",
265 cmd, size, block, line, field);
266 }
267 if (start_line<0)
268 start_line=last_line;
269 /* Prints debug info */
270 dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
271 "field=%d\n",
272 start_line, last_line, field);
232 273
233 if (cmd == TM6000_URB_MSG_VIDEO) { 274 if ((start_line<6 && last_line>200) &&
234 if ((block+1)*TM6000_URB_MSG_LEN>linewidth) 275 (last_field != field) ) {
235 cmd = TM6000_URB_MSG_ERR;
236 276
237 /* FIXME: Mounts the image as field0+field1 277 dev->isoc_ctl.nfields++;
238 * It should, instead, check if the user selected 278 if (dev->isoc_ctl.nfields>=2) {
239 * entrelaced or non-entrelaced mode 279 dev->isoc_ctl.nfields=0;
240 */
241 pos= ((line<<1)+field)*linewidth +
242 block*TM6000_URB_MSG_LEN;
243 280
244 /* Don't allow to write out of the buffer */ 281 /* Announces that a new buffer were filled */
245 if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) { 282 buffer_filled (dev, dma_q, *buf);
246 dprintk(dev, V4L2_DEBUG_ISOC, 283 dprintk(dev, V4L2_DEBUG_ISOC,
247 "ERR: size=%d, num=%d, line=%d, " 284 "new buffer filled\n");
248 "field=%d\n", 285 rc=get_next_buf (dma_q, buf);
249 size, block, line, field);
250
251 cmd = TM6000_URB_MSG_ERR;
252 }
253 } else {
254 pos=0;
255 }
256
257 /* Prints debug info */
258 dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
259 " line=%d, field=%d\n",
260 size, block, line, field);
261
262 if ((last_line!=line)&&(last_line+1!=line) &&
263 (cmd != TM6000_URB_MSG_ERR) ) {
264 if (cmd != TM6000_URB_MSG_VIDEO) {
265 dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, "
266 "size=%d, num=%d, line=%d, field=%d\n",
267 cmd, size, block, line, field);
268 }
269 if (start_line<0)
270 start_line=last_line;
271 /* Prints debug info */
272 dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
273 "field=%d\n",
274 start_line, last_line, field);
275
276 if ((start_line<6 && last_line>200) &&
277 (last_field != field) ) {
278
279 dev->isoc_ctl.nfields++;
280 if (dev->isoc_ctl.nfields>=2) {
281 dev->isoc_ctl.nfields=0;
282
283 /* Announces that a new buffer were filled */
284 buffer_filled (dev, dma_q, *buf);
285 dprintk(dev, V4L2_DEBUG_ISOC,
286 "new buffer filled\n");
287 rc=get_next_buf (dma_q, buf);
288 }
289 } 286 }
290
291 start_line=line;
292 last_field=field;
293 } 287 }
294 last_line=line;
295 288
296 pktsize = TM6000_URB_MSG_LEN; 289 start_line=line;
297 } else { 290 last_field=field;
298 /* Continue the last copy */
299 cmd = dev->isoc_ctl.cmd;
300 size= dev->isoc_ctl.size;
301 pos = dev->isoc_ctl.pos;
302 pktsize = dev->isoc_ctl.pktsize;
303 } 291 }
292 last_line=line;
293
294 pktsize = TM6000_URB_MSG_LEN;
304 295
305 cpysize=(endp-(*ptr)>size)?size:endp-(*ptr); 296 cpysize=(endp-(*ptr)>size)?size:endp-(*ptr);
306 297
@@ -325,19 +316,7 @@ printk ("%ld: cmd=%s, size=%d\n", jiffies,
325 tm6000_msg_type[cmd],size); 316 tm6000_msg_type[cmd],size);
326 } 317 }
327 } 318 }
328 if (cpysize<size) { 319 (*ptr)+=cpysize;
329 /* End of URB packet, but cmd processing is not
330 * complete. Preserve the state for a next packet
331 */
332 dev->isoc_ctl.pos = pos+cpysize;
333 dev->isoc_ctl.size= size-cpysize;
334 dev->isoc_ctl.cmd = cmd;
335 dev->isoc_ctl.pktsize = pktsize-cpysize;
336 (*ptr)+=cpysize;
337 } else {
338 dev->isoc_ctl.cmd = 0;
339 (*ptr)+=pktsize;
340 }
341 320
342 return rc; 321 return rc;
343} 322}
@@ -347,57 +326,73 @@ static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
347{ 326{
348 struct tm6000_dmaqueue *dma_q = urb->context; 327 struct tm6000_dmaqueue *dma_q = urb->context;
349 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); 328 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
350 u8 *ptr=data, *endp=data+len; 329 u8 *ptr, *endp;
351 unsigned long header=0; 330 unsigned long header=0;
352 int rc=0; 331 int rc=0, size;
353 332
354 for (ptr=data; ptr<endp;) { 333 /* Process pending data */
355 if (!dev->isoc_ctl.cmd) { 334 if (dev->isoc_ctl.pending) {
356 u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf; 335 memcpy(dev->isoc_ctl.tbuf + dev->isoc_ctl.len, ptr,
357 /* FIXME: This seems very complex 336 sizeof(dev->isoc_ctl.tbuf) - dev->isoc_ctl.len);
358 * It just recovers up to 3 bytes of the header that 337
359 * might be at the previous packet 338 /* Seek for sync */
360 */ 339 endp = dev->isoc_ctl.tbuf + sizeof(dev->isoc_ctl.tbuf);
361 if (dev->isoc_ctl.tmp_buf_len) { 340 for (ptr = dev->isoc_ctl.tbuf;ptr < endp - 3;ptr++) {
362 while (dev->isoc_ctl.tmp_buf_len) { 341 if (*(ptr + 3) == 0x47)
363 if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) { 342 break;
364 break; 343 }
365 } 344 header=*(unsigned long *)ptr;
366 p++; 345 size = (((header & 0x7e) << 1) - 1) * 4;
367 dev->isoc_ctl.tmp_buf_len--; 346 if(size > TM6000_URB_MSG_LEN)
368 } 347 size = TM6000_URB_MSG_LEN;
369 if (dev->isoc_ctl.tmp_buf_len) { 348
370 memcpy (&header,p, 349 if (ptr+3+size >= endp) {
371 dev->isoc_ctl.tmp_buf_len); 350 printk(KERN_ERR "tm6000: broken data\n");
372 memcpy (((u8 *)header)+ 351 ptr = data;
373 dev->isoc_ctl.tmp_buf, 352 goto process_new_uri;
374 ptr, 353 }
375 4-dev->isoc_ctl.tmp_buf_len); 354 ptr+=4;
376 ptr+=4-dev->isoc_ctl.tmp_buf_len; 355
377 goto HEADER; 356 /* Copy or continue last copy */
378 } 357 rc=copy_packet(urb, header, &ptr, endp, out_p, buf);
379 } 358 if (rc<0) {
359 buf=NULL;
360 printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
361 jiffies);
362 return rc;
363 }
364 dev->isoc_ctl.pending = 0;
365 ptr = data + (ptr - dev->isoc_ctl.tbuf);
366 } else
367 ptr = data;
368
369process_new_uri:
370 endp = data + len;
371 while (ptr<endp) {
372 if (!dev->isoc_ctl.pending) {
380 /* Seek for sync */ 373 /* Seek for sync */
381 for (;ptr<endp-3;ptr++) { 374 for (;ptr<endp-3;ptr++) {
382 if (*(ptr+3)==0x47) 375 if (*(ptr+3)==0x47)
383 break; 376 break;
384 } 377 }
378 header=*(unsigned long *)ptr;
379 size = (((header & 0x7e)<<1) -1) *4;
380 if(size>TM6000_URB_MSG_LEN)
381 size = TM6000_URB_MSG_LEN;
382
383 if (ptr+3+size >= endp) {
384 int len = endp - ptr;
385 385
386 if (ptr+3>=endp) { 386 memcpy (dev->isoc_ctl.tbuf, ptr, len);
387 dev->isoc_ctl.tmp_buf_len=endp-ptr; 387 dev->isoc_ctl.len = len;
388 memcpy (&dev->isoc_ctl.tmp_buf,ptr, 388 dev->isoc_ctl.pending = 1;
389 dev->isoc_ctl.tmp_buf_len);
390 dev->isoc_ctl.cmd=0;
391 return rc; 389 return rc;
392 } 390 }
393
394 /* Get message header */
395 header=*(unsigned long *)ptr;
396 ptr+=4; 391 ptr+=4;
397 } 392 }
398HEADER: 393
399 /* Copy or continue last copy */ 394 /* Copy or continue last copy */
400 rc=copy_packet(urb,header,&ptr,endp,out_p,buf); 395 rc=copy_packet(urb, header, &ptr, endp, out_p, buf);
401 if (rc<0) { 396 if (rc<0) {
402 buf=NULL; 397 buf=NULL;
403 printk(KERN_ERR "tm6000: buffer underrun at %ld\n", 398 printk(KERN_ERR "tm6000: buffer underrun at %ld\n",