Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (12482): firedtv: add PID filtering for SW zigzag retune

The AVC protocol uses the same command for tuning and PID filtering and
since dvb-core uses a software zigzagging to do automatic retuning this
could cause all PID filters to be cleared. PID filter information is
now included in all DSD commands to the card.

Background:

There is a problem in the firedtv driver that causes recordings to stop
if the SW zigzag algorithm in dvb-core kicks in with a retune after the
application has set up the PID filters. Since tuning and setting PID
filters uses the same AVC command (DSD) and only the replace subfunction
is supported by the card, it is not possible to do a retune without
setting the PID filters. This means that the PID filtering has to be
sent in each tune.

This problem applies to C and T cards since S and S2 cards tune using a
vendor specific command. The patch corrects the problem by sending the
PID list in each tune. I have tested it on my T card with a good
result.

How to trigger problem: Zap to a channel and output AV to a file, e.g.
"tzap -c channels.conf SVT1 -r -o SVT1.ts". After a short while, pull
the antenna cable from the card. The lock on the channel will disappear
and the TS file will stop increasing in size. Wait a couple of seconds.
Replug the cable again. You will get a lock on the channel again, but
the TS file will never increase in size agains sinze no PIDS are
filtered.

Tested with kaffeine with DVB-T and DVB-C: Fixes retuning after antenna
was plugged out and back in with DVB-T. Does not fix this with DVB-C,
but also doesn't regress on DVB-C.

Signed-off-by: Henrik Kurelid <henrik@kurelid.se>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Henrik Kurelid and committed by
Mauro Carvalho Chehab
166987c6 114323ed

+30 -10
+30 -10
drivers/media/dvb/firewire/firedtv-avc.c
··· 254 254 return 0; 255 255 } 256 256 257 + static int add_pid_filter(struct firedtv *fdtv, u8 *operand) 258 + { 259 + int i, n, pos = 1; 260 + 261 + for (i = 0, n = 0; i < 16; i++) { 262 + if (test_bit(i, &fdtv->channel_active)) { 263 + operand[pos++] = 0x13; /* flowfunction relay */ 264 + operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ 265 + operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f; 266 + operand[pos++] = fdtv->channel_pid[i] & 0xff; 267 + operand[pos++] = 0x00; /* tableID */ 268 + operand[pos++] = 0x00; /* filter_length */ 269 + n++; 270 + } 271 + } 272 + operand[0] = n; 273 + 274 + return pos; 275 + } 276 + 257 277 /* 258 278 * tuning command for setting the relative LNB frequency 259 279 * (not supported by the AVC standard) ··· 336 316 } 337 317 } 338 318 339 - static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, 319 + static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv, 320 + struct dvb_frontend_parameters *params, 340 321 struct avc_command_frame *c) 341 322 { 342 323 c->opcode = AVC_OPCODE_DSD; ··· 399 378 400 379 c->operand[20] = 0x00; 401 380 c->operand[21] = 0x00; 402 - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ 403 - c->operand[22] = 0x00; 404 381 405 - c->length = 28; 382 + /* Add PIDs to filter */ 383 + c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4); 406 384 } 407 385 408 - static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, 386 + static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv, 387 + struct dvb_frontend_parameters *params, 409 388 struct avc_command_frame *c) 410 389 { 411 390 struct dvb_ofdm_parameters *ofdm = &params->u.ofdm; ··· 502 481 503 482 c->operand[15] = 0x00; /* network_ID[0] */ 504 483 c->operand[16] = 0x00; /* network_ID[1] */ 505 - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ 506 - c->operand[17] = 0x00; 507 484 508 - c->length = 24; 485 + /* Add PIDs to filter */ 486 + c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4); 509 487 } 510 488 511 489 int avc_tuner_dsd(struct firedtv *fdtv, ··· 522 502 switch (fdtv->type) { 523 503 case FIREDTV_DVB_S: 524 504 case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break; 525 - case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break; 526 - case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break; 505 + case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break; 506 + case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break; 527 507 default: 528 508 BUG(); 529 509 }