diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-06-20 05:09:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:17:31 -0400 |
commit | 3c86cf7a7d323019a7942df8bacf47c9fd2c31fa (patch) | |
tree | 8ed9ecc206eef28319d633d38432aab310e98219 /drivers | |
parent | 6a052c84342dd047226ecad0e1aa4e4b37d45a6c (diff) |
V4L/DVB (12215): saa6588: conform to the final RDS spec.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/saa6588.c | 60 |
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index c25e81af5ce0..c3e96f070973 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c | |||
@@ -40,7 +40,7 @@ | |||
40 | /* insmod options */ | 40 | /* insmod options */ |
41 | static unsigned int debug; | 41 | static unsigned int debug; |
42 | static unsigned int xtal; | 42 | static unsigned int xtal; |
43 | static unsigned int rbds; | 43 | static unsigned int mmbs; |
44 | static unsigned int plvl; | 44 | static unsigned int plvl; |
45 | static unsigned int bufblocks = 100; | 45 | static unsigned int bufblocks = 100; |
46 | 46 | ||
@@ -48,8 +48,8 @@ module_param(debug, int, 0644); | |||
48 | MODULE_PARM_DESC(debug, "enable debug messages"); | 48 | MODULE_PARM_DESC(debug, "enable debug messages"); |
49 | module_param(xtal, int, 0); | 49 | module_param(xtal, int, 0); |
50 | MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); | 50 | MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); |
51 | module_param(rbds, int, 0); | 51 | module_param(mmbs, int, 0); |
52 | MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0"); | 52 | MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on"); |
53 | module_param(plvl, int, 0); | 53 | module_param(plvl, int, 0); |
54 | MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); | 54 | MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); |
55 | module_param(bufblocks, int, 0); | 55 | module_param(bufblocks, int, 0); |
@@ -78,6 +78,7 @@ struct saa6588 { | |||
78 | unsigned char last_blocknum; | 78 | unsigned char last_blocknum; |
79 | wait_queue_head_t read_queue; | 79 | wait_queue_head_t read_queue; |
80 | int data_available_for_read; | 80 | int data_available_for_read; |
81 | u8 sync; | ||
81 | }; | 82 | }; |
82 | 83 | ||
83 | static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd) | 84 | static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd) |
@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s) | |||
261 | unsigned char tmp; | 262 | unsigned char tmp; |
262 | 263 | ||
263 | /* Although we only need 3 bytes, we have to read at least 6. | 264 | /* Although we only need 3 bytes, we have to read at least 6. |
264 | SAA6588 returns garbage otherwise */ | 265 | SAA6588 returns garbage otherwise. */ |
265 | if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) { | 266 | if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) { |
266 | if (debug > 1) | 267 | if (debug > 1) |
267 | dprintk(PREFIX "read error!\n"); | 268 | dprintk(PREFIX "read error!\n"); |
268 | return; | 269 | return; |
269 | } | 270 | } |
270 | 271 | ||
272 | s->sync = tmpbuf[0] & 0x10; | ||
273 | if (!s->sync) | ||
274 | return; | ||
271 | blocknum = tmpbuf[0] >> 5; | 275 | blocknum = tmpbuf[0] >> 5; |
272 | if (blocknum == s->last_blocknum) { | 276 | if (blocknum == s->last_blocknum) { |
273 | if (debug > 3) | 277 | if (debug > 3) |
@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s) | |||
286 | occurred during reception of this block. | 290 | occurred during reception of this block. |
287 | Bit 6: Corrected bit. Indicates that an error was | 291 | Bit 6: Corrected bit. Indicates that an error was |
288 | corrected for this data block. | 292 | corrected for this data block. |
289 | Bits 5-3: Received Offset. Indicates the offset received | 293 | Bits 5-3: Same as bits 0-2. |
290 | by the sync system. | 294 | Bits 2-0: Block number. |
291 | Bits 2-0: Offset Name. Indicates the offset applied to this data. | ||
292 | 295 | ||
293 | SAA6588 byte order is Status-MSB-LSB, so we have to swap the | 296 | SAA6588 byte order is Status-MSB-LSB, so we have to swap the |
294 | first and the last of the 3 bytes block. | 297 | first and the last of the 3 bytes block. |
@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s) | |||
298 | tmpbuf[2] = tmpbuf[0]; | 301 | tmpbuf[2] = tmpbuf[0]; |
299 | tmpbuf[0] = tmp; | 302 | tmpbuf[0] = tmp; |
300 | 303 | ||
304 | /* Map 'Invalid block E' to 'Invalid Block' */ | ||
305 | if (blocknum == 6) | ||
306 | blocknum = V4L2_RDS_BLOCK_INVALID; | ||
307 | /* And if are not in mmbs mode, then 'Block E' is also mapped | ||
308 | to 'Invalid Block'. As far as I can tell MMBS is discontinued, | ||
309 | and if there is ever a need to support E blocks, then please | ||
310 | contact the linux-media mailinglist. */ | ||
311 | else if (!mmbs && blocknum == 5) | ||
312 | blocknum = V4L2_RDS_BLOCK_INVALID; | ||
301 | tmp = blocknum; | 313 | tmp = blocknum; |
302 | tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ | 314 | tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ |
303 | if ((tmpbuf[2] & 0x03) == 0x03) | 315 | if ((tmpbuf[2] & 0x03) == 0x03) |
304 | tmp |= 0x80; /* uncorrectable error */ | 316 | tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */ |
305 | else if ((tmpbuf[2] & 0x03) != 0x00) | 317 | else if ((tmpbuf[2] & 0x03) != 0x00) |
306 | tmp |= 0x40; /* corrected error */ | 318 | tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */ |
307 | tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ | 319 | tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ |
308 | 320 | ||
309 | spin_lock_irqsave(&s->lock, flags); | 321 | spin_lock_irqsave(&s->lock, flags); |
@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work) | |||
321 | schedule_delayed_work(&s->work, msecs_to_jiffies(20)); | 333 | schedule_delayed_work(&s->work, msecs_to_jiffies(20)); |
322 | } | 334 | } |
323 | 335 | ||
324 | static int saa6588_configure(struct saa6588 *s) | 336 | static void saa6588_configure(struct saa6588 *s) |
325 | { | 337 | { |
326 | struct i2c_client *client = v4l2_get_subdevdata(&s->sd); | 338 | struct i2c_client *client = v4l2_get_subdevdata(&s->sd); |
327 | unsigned char buf[3]; | 339 | unsigned char buf[3]; |
328 | int rc; | 340 | int rc; |
329 | 341 | ||
330 | buf[0] = cSyncRestart; | 342 | buf[0] = cSyncRestart; |
331 | if (rbds) | 343 | if (mmbs) |
332 | buf[0] |= cProcessingModeRBDS; | 344 | buf[0] |= cProcessingModeRBDS; |
333 | 345 | ||
334 | buf[1] = cFlywheelDefault; | 346 | buf[1] = cFlywheelDefault; |
@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s) | |||
374 | rc = i2c_master_send(client, buf, 3); | 386 | rc = i2c_master_send(client, buf, 3); |
375 | if (rc != 3) | 387 | if (rc != 3) |
376 | printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); | 388 | printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); |
377 | |||
378 | return 0; | ||
379 | } | 389 | } |
380 | 390 | ||
381 | /* ---------------------------------------------------------------------- */ | 391 | /* ---------------------------------------------------------------------- */ |
@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) | |||
416 | return 0; | 426 | return 0; |
417 | } | 427 | } |
418 | 428 | ||
429 | static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | ||
430 | { | ||
431 | struct saa6588 *s = to_saa6588(sd); | ||
432 | |||
433 | vt->capability |= V4L2_TUNER_CAP_RDS; | ||
434 | if (s->sync) | ||
435 | vt->rxsubchans |= V4L2_TUNER_SUB_RDS; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | ||
440 | { | ||
441 | struct saa6588 *s = to_saa6588(sd); | ||
442 | |||
443 | saa6588_configure(s); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
419 | static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 447 | static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
420 | { | 448 | { |
421 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 449 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = { | |||
430 | .ioctl = saa6588_ioctl, | 458 | .ioctl = saa6588_ioctl, |
431 | }; | 459 | }; |
432 | 460 | ||
461 | static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = { | ||
462 | .g_tuner = saa6588_g_tuner, | ||
463 | .s_tuner = saa6588_s_tuner, | ||
464 | }; | ||
465 | |||
433 | static const struct v4l2_subdev_ops saa6588_ops = { | 466 | static const struct v4l2_subdev_ops saa6588_ops = { |
434 | .core = &saa6588_core_ops, | 467 | .core = &saa6588_core_ops, |
468 | .tuner = &saa6588_tuner_ops, | ||
435 | }; | 469 | }; |
436 | 470 | ||
437 | /* ---------------------------------------------------------------------- */ | 471 | /* ---------------------------------------------------------------------- */ |