diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-01-08 09:25:57 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:40:05 -0400 |
commit | 6eb5c8a6c82d7c753ea52df94ea2ff096b5aba96 (patch) | |
tree | 12d4a98f98b18e1700479b656fdce97ac83643b5 /drivers | |
parent | 29c389be1ceb714739cdcd41fec6547d19b32864 (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.h | 1 | ||||
-rw-r--r-- | drivers/staging/tm6000/tm6000-usb-isoc.h | 12 | ||||
-rw-r--r-- | 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 @@ | |||
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 | ||
81 | enum { | 80 | enum { |
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 | |||
22 | struct usb_isoc_ctl { | 24 | struct 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 | |||
369 | process_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 | } |
398 | HEADER: | 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", |