1/* 2 * Driver for the SAA5246A or SAA5281 Teletext (=Videotext) decoder chips from 3 * Philips. 4 * 5 * Only capturing of Teletext pages is tested. The videotext chips also have a 6 * TV output but my hardware doesn't use it. For this reason this driver does 7 * not support changing any TV display settings. 8 * 9 * Copyright (C) 2004 Michael Geng <linux@MichaelGeng.de> 10 * 11 * Derived from 12 * 13 * saa5249 driver 14 * Copyright (C) 1998 Richard Guenther 15 * <richard.guenther@student.uni-tuebingen.de> 16 * 17 * with changes by 18 * Alan Cox <alan@lxorguk.ukuu.org.uk> 19 * 20 * and 21 * 22 * vtx.c 23 * Copyright (C) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de> 24 * 25 * This program is free software; you can redistribute it and/or modify 26 * it under the terms of the GNU General Public License as published by 27 * the Free Software Foundation; either version 2 of the License, or 28 * (at your option) any later version. 29 * 30 * This program is distributed in the hope that it will be useful, 31 * but WITHOUT ANY WARRANTY; without even the implied warranty of 32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 * GNU General Public License for more details. 34 * 35 * You should have received a copy of the GNU General Public License 36 * along with this program; if not, write to the Free Software 37 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 38 * USA. 39 */ 40 41#include <linux/module.h> 42#include <linux/kernel.h> 43#include <linux/mm.h> 44#include <linux/init.h> 45#include <linux/i2c.h> 46#include <linux/slab.h> 47#include <linux/mutex.h> 48#include <linux/videotext.h> 49#include <linux/videodev2.h> 50#include <media/v4l2-device.h> 51#include <media/v4l2-chip-ident.h> 52#include <media/v4l2-ioctl.h> 53#include <media/v4l2-i2c-drv.h> 54 55MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>"); 56MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver"); 57MODULE_LICENSE("GPL"); 58 59#define MAJOR_VERSION 1 /* driver major version number */ 60#define MINOR_VERSION 8 /* driver minor version number */ 61 62/* Number of DAUs = number of pages that can be searched at the same time. */ 63#define NUM_DAUS 4 64 65#define NUM_ROWS_PER_PAGE 40 66 67/* first column is 0 (not 1) */ 68#define POS_TIME_START 32 69#define POS_TIME_END 39 70 71#define POS_HEADER_START 7 72#define POS_HEADER_END 31 73 74/* Returns 'true' if the part of the videotext page described with req contains 75 (at least parts of) the time field */ 76#define REQ_CONTAINS_TIME(p_req) \ 77 ((p_req)->start <= POS_TIME_END && \ 78 (p_req)->end >= POS_TIME_START) 79 80/* Returns 'true' if the part of the videotext page described with req contains 81 (at least parts of) the page header */ 82#define REQ_CONTAINS_HEADER(p_req) \ 83 ((p_req)->start <= POS_HEADER_END && \ 84 (p_req)->end >= POS_HEADER_START) 85 86/*****************************************************************************/ 87/* Mode register numbers of the SAA5246A */ 88/*****************************************************************************/ 89#define SAA5246A_REGISTER_R0 0 90#define SAA5246A_REGISTER_R1 1 91#define SAA5246A_REGISTER_R2 2 92#define SAA5246A_REGISTER_R3 3 93#define SAA5246A_REGISTER_R4 4 94#define SAA5246A_REGISTER_R5 5 95#define SAA5246A_REGISTER_R6 6 96#define SAA5246A_REGISTER_R7 7 97#define SAA5246A_REGISTER_R8 8 98#define SAA5246A_REGISTER_R9 9 99#define SAA5246A_REGISTER_R10 10 100#define SAA5246A_REGISTER_R11 11 101#define SAA5246A_REGISTER_R11B 11 102 103/* SAA5246A mode registers often autoincrement to the next register. 104 Therefore we use variable argument lists. The following macro indicates 105 the end of a command list. */ 106#define COMMAND_END (-1) 107 108/*****************************************************************************/ 109/* Contents of the mode registers of the SAA5246A */ 110/*****************************************************************************/ 111/* Register R0 (Advanced Control) */ 112#define R0_SELECT_R11 0x00 113#define R0_SELECT_R11B 0x01 114 115#define R0_PLL_TIME_CONSTANT_LONG 0x00 116#define R0_PLL_TIME_CONSTANT_SHORT 0x02 117 118#define R0_ENABLE_nODD_EVEN_OUTPUT 0x00 119#define R0_DISABLE_nODD_EVEN_OUTPUT 0x04 120 121#define R0_ENABLE_HDR_POLL 0x00 122#define R0_DISABLE_HDR_POLL 0x10 123 124#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00 125#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x20 126 127#define R0_NO_FREE_RUN_PLL 0x00 128#define R0_FREE_RUN_PLL 0x40 129 130#define R0_NO_AUTOMATIC_FASTEXT_PROMPT 0x00 131#define R0_AUTOMATIC_FASTEXT_PROMPT 0x80 132 133/* Register R1 (Mode) */ 134#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES 0x00 135#define R1_NON_INTERLACED_312_313_LINES 0x01 136#define R1_NON_INTERLACED_312_312_LINES 0x02 137#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE 0x03 138#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE 0x07 139 140#define R1_DEW 0x00 141#define R1_FULL_FIELD 0x08 142 143#define R1_EXTENDED_PACKET_DISABLE 0x00 144#define R1_EXTENDED_PACKET_ENABLE 0x10 145 146#define R1_DAUS_ALL_ON 0x00 147#define R1_DAUS_ALL_OFF 0x20 148 149#define R1_7_BITS_PLUS_PARITY 0x00 150#define R1_8_BITS_NO_PARITY 0x40 151 152#define R1_VCS_TO_SCS 0x00 153#define R1_NO_VCS_TO_SCS 0x80 154 155/* Register R2 (Page request address) */ 156#define R2_IN_R3_SELECT_PAGE_HUNDREDS 0x00 157#define R2_IN_R3_SELECT_PAGE_TENS 0x01 158#define R2_IN_R3_SELECT_PAGE_UNITS 0x02 159#define R2_IN_R3_SELECT_HOURS_TENS 0x03 160#define R2_IN_R3_SELECT_HOURS_UNITS 0x04 161#define R2_IN_R3_SELECT_MINUTES_TENS 0x05 162#define R2_IN_R3_SELECT_MINUTES_UNITS 0x06 163 164#define R2_DAU_0 0x00 165#define R2_DAU_1 0x10 166#define R2_DAU_2 0x20 167#define R2_DAU_3 0x30 168 169#define R2_BANK_0 0x00 170#define R2_BANK 1 0x40 171 172#define R2_HAMMING_CHECK_ON 0x80 173#define R2_HAMMING_CHECK_OFF 0x00 174 175/* Register R3 (Page request data) */ 176#define R3_PAGE_HUNDREDS_0 0x00 177#define R3_PAGE_HUNDREDS_1 0x01 178#define R3_PAGE_HUNDREDS_2 0x02 179#define R3_PAGE_HUNDREDS_3 0x03 180#define R3_PAGE_HUNDREDS_4 0x04 181#define R3_PAGE_HUNDREDS_5 0x05 182#define R3_PAGE_HUNDREDS_6 0x06 183#define R3_PAGE_HUNDREDS_7 0x07 184 185#define R3_HOLD_PAGE 0x00 186#define R3_UPDATE_PAGE 0x08 187 188#define R3_PAGE_HUNDREDS_DO_NOT_CARE 0x00 189#define R3_PAGE_HUNDREDS_DO_CARE 0x10 190 191#define R3_PAGE_TENS_DO_NOT_CARE 0x00 192#define R3_PAGE_TENS_DO_CARE 0x10 193 194#define R3_PAGE_UNITS_DO_NOT_CARE 0x00 195#define R3_PAGE_UNITS_DO_CARE 0x10 196 197#define R3_HOURS_TENS_DO_NOT_CARE 0x00 198#define R3_HOURS_TENS_DO_CARE 0x10 199 200#define R3_HOURS_UNITS_DO_NOT_CARE 0x00 201#define R3_HOURS_UNITS_DO_CARE 0x10 202 203#define R3_MINUTES_TENS_DO_NOT_CARE 0x00 204#define R3_MINUTES_TENS_DO_CARE 0x10 205 206#define R3_MINUTES_UNITS_DO_NOT_CARE 0x00 207#define R3_MINUTES_UNITS_DO_CARE 0x10 208 209/* Register R4 (Display chapter) */ 210#define R4_DISPLAY_PAGE_0 0x00 211#define R4_DISPLAY_PAGE_1 0x01 212#define R4_DISPLAY_PAGE_2 0x02 213#define R4_DISPLAY_PAGE_3 0x03 214#define R4_DISPLAY_PAGE_4 0x04 215#define R4_DISPLAY_PAGE_5 0x05 216#define R4_DISPLAY_PAGE_6 0x06 217#define R4_DISPLAY_PAGE_7 0x07 218 219/* Register R5 (Normal display control) */ 220#define R5_PICTURE_INSIDE_BOXING_OFF 0x00 221#define R5_PICTURE_INSIDE_BOXING_ON 0x01 222 223#define R5_PICTURE_OUTSIDE_BOXING_OFF 0x00 224#define R5_PICTURE_OUTSIDE_BOXING_ON 0x02 225 226#define R5_TEXT_INSIDE_BOXING_OFF 0x00 227#define R5_TEXT_INSIDE_BOXING_ON 0x04 228 229#define R5_TEXT_OUTSIDE_BOXING_OFF 0x00 230#define R5_TEXT_OUTSIDE_BOXING_ON 0x08 231 232#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00 233#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10 234 235#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00 236#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20 237 238#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00 239#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40 240 241#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00 242#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80 243 244/* Register R6 (Newsflash display) */ 245#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF 0x00 246#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON 0x01 247 248#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF 0x00 249#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON 0x02 250 251#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF 0x00 252#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON 0x04 253 254#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF 0x00 255#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON 0x08 256 257#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00 258#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10 259 260#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00 261#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20 262 263#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00 264#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40 265 266#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00 267#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80 268 269/* Register R7 (Display mode) */ 270#define R7_BOX_OFF_ROW_0 0x00 271#define R7_BOX_ON_ROW_0 0x01 272 273#define R7_BOX_OFF_ROW_1_TO_23 0x00 274#define R7_BOX_ON_ROW_1_TO_23 0x02 275 276#define R7_BOX_OFF_ROW_24 0x00 277#define R7_BOX_ON_ROW_24 0x04 278 279#define R7_SINGLE_HEIGHT 0x00 280#define R7_DOUBLE_HEIGHT 0x08 281 282#define R7_TOP_HALF 0x00 283#define R7_BOTTOM_HALF 0x10 284 285#define R7_REVEAL_OFF 0x00 286#define R7_REVEAL_ON 0x20 287 288#define R7_CURSER_OFF 0x00 289#define R7_CURSER_ON 0x40 290 291#define R7_STATUS_BOTTOM 0x00 292#define R7_STATUS_TOP 0x80 293 294/* Register R8 (Active chapter) */ 295#define R8_ACTIVE_CHAPTER_0 0x00 296#define R8_ACTIVE_CHAPTER_1 0x01 297#define R8_ACTIVE_CHAPTER_2 0x02 298#define R8_ACTIVE_CHAPTER_3 0x03 299#define R8_ACTIVE_CHAPTER_4 0x04 300#define R8_ACTIVE_CHAPTER_5 0x05 301#define R8_ACTIVE_CHAPTER_6 0x06 302#define R8_ACTIVE_CHAPTER_7 0x07 303 304#define R8_CLEAR_MEMORY 0x08 305#define R8_DO_NOT_CLEAR_MEMORY 0x00 306 307/* Register R9 (Curser row) */ 308#define R9_CURSER_ROW_0 0x00 309#define R9_CURSER_ROW_1 0x01 310#define R9_CURSER_ROW_2 0x02 311#define R9_CURSER_ROW_25 0x19 312 313/* Register R10 (Curser column) */ 314#define R10_CURSER_COLUMN_0 0x00 315#define R10_CURSER_COLUMN_6 0x06 316#define R10_CURSER_COLUMN_8 0x08 317 318/*****************************************************************************/ 319/* Row 25 control data in column 0 to 9 */ 320/*****************************************************************************/ 321#define ROW25_COLUMN0_PAGE_UNITS 0x0F 322 323#define ROW25_COLUMN1_PAGE_TENS 0x0F 324 325#define ROW25_COLUMN2_MINUTES_UNITS 0x0F 326 327#define ROW25_COLUMN3_MINUTES_TENS 0x07 328#define ROW25_COLUMN3_DELETE_PAGE 0x08 329 330#define ROW25_COLUMN4_HOUR_UNITS 0x0F 331 332#define ROW25_COLUMN5_HOUR_TENS 0x03 333#define ROW25_COLUMN5_INSERT_HEADLINE 0x04 334#define ROW25_COLUMN5_INSERT_SUBTITLE 0x08 335 336#define ROW25_COLUMN6_SUPPRESS_HEADER 0x01 337#define ROW25_COLUMN6_UPDATE_PAGE 0x02 338#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE 0x04 339#define ROW25_COLUMN6_SUPPRESS_DISPLAY 0x08 340 341#define ROW25_COLUMN7_SERIAL_MODE 0x01 342#define ROW25_COLUMN7_CHARACTER_SET 0x0E 343 344#define ROW25_COLUMN8_PAGE_HUNDREDS 0x07 345#define ROW25_COLUMN8_PAGE_NOT_FOUND 0x10 346 347#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR 0x20 348 349#define ROW25_COLUMN0_TO_7_HAMMING_ERROR 0x10 350 351/*****************************************************************************/ 352/* Helper macros for extracting page, hour and minute digits */ 353/*****************************************************************************/ 354/* BYTE_POS 0 is at row 0, column 0, 355 BYTE_POS 1 is at row 0, column 1, 356 BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40) 357 BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40), 358 ... */ 359#define ROW(BYTE_POS) (BYTE_POS / NUM_ROWS_PER_PAGE) 360#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE) 361 362/*****************************************************************************/ 363/* Helper macros for extracting page, hour and minute digits */ 364/*****************************************************************************/ 365/* Macros for extracting hundreds, tens and units of a page number which 366 must be in the range 0 ... 0x799. 367 Note that page is coded in hexadecimal, i.e. 0x123 means page 123. 368 page 0x.. means page 8.. */ 369#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7) 370#define TENS_OF_PAGE(page) (((page) / 0x10) & 0xF) 371#define UNITS_OF_PAGE(page) ((page) & 0xF) 372 373/* Macros for extracting tens and units of a hour information which 374 must be in the range 0 ... 0x24. 375 Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */ 376#define TENS_OF_HOUR(hour) ((hour) / 0x10) 377#define UNITS_OF_HOUR(hour) ((hour) & 0xF) 378 379/* Macros for extracting tens and units of a minute information which 380 must be in the range 0 ... 0x59. 381 Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */ 382#define TENS_OF_MINUTE(minute) ((minute) / 0x10) 383#define UNITS_OF_MINUTE(minute) ((minute) & 0xF) 384 385#define HOUR_MAX 0x23 386#define MINUTE_MAX 0x59 387#define PAGE_MAX 0x8FF 388 389 390struct saa5246a_device 391{ 392 struct v4l2_subdev sd; 393 struct video_device *vdev; 394 u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE]; 395 int is_searching[NUM_DAUS]; 396 unsigned long in_use; 397 struct mutex lock; 398}; 399 400static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd) 401{ 402 return container_of(sd, struct saa5246a_device, sd); 403} 404 405static struct video_device saa_template; /* Declared near bottom */ 406 407/* 408 * I2C interfaces 409 */ 410 411static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data) 412{ 413 struct i2c_client *client = v4l2_get_subdevdata(&t->sd); 414 char buf[64]; 415 416 buf[0] = reg; 417 memcpy(buf+1, data, count); 418 419 if (i2c_master_send(client, buf, count + 1) == count + 1) 420 return 0; 421 return -1; 422} 423 424static int i2c_senddata(struct saa5246a_device *t, ...) 425{ 426 unsigned char buf[64]; 427 int v; 428 int ct = 0; 429 va_list argp; 430 va_start(argp, t); 431 432 while ((v = va_arg(argp, int)) != -1) 433 buf[ct++] = v; 434 435 va_end(argp); 436 return i2c_sendbuf(t, buf[0], ct-1, buf+1); 437} 438 439/* Get count number of bytes from I��C-device at address adr, store them in buf. 440 * Start & stop handshaking is done by this routine, ack will be sent after the 441 * last byte to inhibit further sending of data. If uaccess is 'true', data is 442 * written to user-space with put_user. Returns -1 if I��C-device didn't send 443 * acknowledge, 0 otherwise 444 */ 445static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf) 446{ 447 struct i2c_client *client = v4l2_get_subdevdata(&t->sd); 448 449 if (i2c_master_recv(client, buf, count) != count) 450 return -1; 451 return 0; 452} 453 454/* When a page is found then the not FOUND bit in one of the status registers 455 * of the SAA5264A chip is cleared. Unfortunately this bit is not set 456 * automatically when a new page is requested. Instead this function must be 457 * called after a page has been requested. 458 * 459 * Return value: 0 if successful 460 */ 461static int saa5246a_clear_found_bit(struct saa5246a_device *t, 462 unsigned char dau_no) 463{ 464 unsigned char row_25_column_8; 465 466 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 467 468 dau_no | 469 R8_DO_NOT_CLEAR_MEMORY, 470 471 R9_CURSER_ROW_25, 472 473 R10_CURSER_COLUMN_8, 474 475 COMMAND_END) || 476 i2c_getdata(t, 1, &row_25_column_8)) 477 { 478 return -EIO; 479 } 480 row_25_column_8 |= ROW25_COLUMN8_PAGE_NOT_FOUND; 481 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 482 483 dau_no | 484 R8_DO_NOT_CLEAR_MEMORY, 485 486 R9_CURSER_ROW_25, 487 488 R10_CURSER_COLUMN_8, 489 490 row_25_column_8, 491 492 COMMAND_END)) 493 { 494 return -EIO; 495 } 496 497 return 0; 498} 499 500/* Requests one videotext page as described in req. The fields of req are 501 * checked and an error is returned if something is invalid. 502 * 503 * Return value: 0 if successful 504 */ 505static int saa5246a_request_page(struct saa5246a_device *t, 506 vtx_pagereq_t *req) 507{ 508 if (req->pagemask < 0 || req->pagemask >= PGMASK_MAX) 509 return -EINVAL; 510 if (req->pagemask & PGMASK_PAGE) 511 if (req->page < 0 || req->page > PAGE_MAX) 512 return -EINVAL; 513 if (req->pagemask & PGMASK_HOUR) 514 if (req->hour < 0 || req->hour > HOUR_MAX) 515 return -EINVAL; 516 if (req->pagemask & PGMASK_MINUTE) 517 if (req->minute < 0 || req->minute > MINUTE_MAX) 518 return -EINVAL; 519 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS) 520 return -EINVAL; 521 522 if (i2c_senddata(t, SAA5246A_REGISTER_R2, 523 524 R2_IN_R3_SELECT_PAGE_HUNDREDS | 525 req->pgbuf << 4 | 526 R2_BANK_0 | 527 R2_HAMMING_CHECK_OFF, 528 529 HUNDREDS_OF_PAGE(req->page) | 530 R3_HOLD_PAGE | 531 (req->pagemask & PG_HUND ? 532 R3_PAGE_HUNDREDS_DO_CARE : 533 R3_PAGE_HUNDREDS_DO_NOT_CARE), 534 535 TENS_OF_PAGE(req->page) | 536 (req->pagemask & PG_TEN ? 537 R3_PAGE_TENS_DO_CARE : 538 R3_PAGE_TENS_DO_NOT_CARE), 539 540 UNITS_OF_PAGE(req->page) | 541 (req->pagemask & PG_UNIT ? 542 R3_PAGE_UNITS_DO_CARE : 543 R3_PAGE_UNITS_DO_NOT_CARE), 544 545 TENS_OF_HOUR(req->hour) | 546 (req->pagemask & HR_TEN ? 547 R3_HOURS_TENS_DO_CARE : 548 R3_HOURS_TENS_DO_NOT_CARE), 549 550 UNITS_OF_HOUR(req->hour) | 551 (req->pagemask & HR_UNIT ? 552 R3_HOURS_UNITS_DO_CARE : 553 R3_HOURS_UNITS_DO_NOT_CARE), 554 555 TENS_OF_MINUTE(req->minute) | 556 (req->pagemask & MIN_TEN ? 557 R3_MINUTES_TENS_DO_CARE : 558 R3_MINUTES_TENS_DO_NOT_CARE), 559 560 UNITS_OF_MINUTE(req->minute) | 561 (req->pagemask & MIN_UNIT ? 562 R3_MINUTES_UNITS_DO_CARE : 563 R3_MINUTES_UNITS_DO_NOT_CARE), 564 565 COMMAND_END) || i2c_senddata(t, SAA5246A_REGISTER_R2, 566 567 R2_IN_R3_SELECT_PAGE_HUNDREDS | 568 req->pgbuf << 4 | 569 R2_BANK_0 | 570 R2_HAMMING_CHECK_OFF, 571 572 HUNDREDS_OF_PAGE(req->page) | 573 R3_UPDATE_PAGE | 574 (req->pagemask & PG_HUND ? 575 R3_PAGE_HUNDREDS_DO_CARE : 576 R3_PAGE_HUNDREDS_DO_NOT_CARE), 577 578 COMMAND_END)) 579 { 580 return -EIO; 581 } 582 583 t->is_searching[req->pgbuf] = true; 584 return 0; 585} 586 587/* This routine decodes the page number from the infobits contained in line 25. 588 * 589 * Parameters: 590 * infobits: must be bits 0 to 9 of column 25 591 * 592 * Return value: page number coded in hexadecimal, i. e. page 123 is coded 0x123 593 */ 594static inline int saa5246a_extract_pagenum_from_infobits( 595 unsigned char infobits[10]) 596{ 597 int page_hundreds, page_tens, page_units; 598 599 page_units = infobits[0] & ROW25_COLUMN0_PAGE_UNITS; 600 page_tens = infobits[1] & ROW25_COLUMN1_PAGE_TENS; 601 page_hundreds = infobits[8] & ROW25_COLUMN8_PAGE_HUNDREDS; 602 603 /* page 0x.. means page 8.. */ 604 if (page_hundreds == 0) 605 page_hundreds = 8; 606 607 return((page_hundreds << 8) | (page_tens << 4) | page_units); 608} 609 610/* Decodes the hour from the infobits contained in line 25. 611 * 612 * Parameters: 613 * infobits: must be bits 0 to 9 of column 25 614 * 615 * Return: hour coded in hexadecimal, i. e. 12h is coded 0x12 616 */ 617static inline int saa5246a_extract_hour_from_infobits( 618 unsigned char infobits[10]) 619{ 620 int hour_tens, hour_units; 621 622 hour_units = infobits[4] & ROW25_COLUMN4_HOUR_UNITS; 623 hour_tens = infobits[5] & ROW25_COLUMN5_HOUR_TENS; 624 625 return((hour_tens << 4) | hour_units); 626} 627 628/* Decodes the minutes from the infobits contained in line 25. 629 * 630 * Parameters: 631 * infobits: must be bits 0 to 9 of column 25 632 * 633 * Return: minutes coded in hexadecimal, i. e. 10min is coded 0x10 634 */ 635static inline int saa5246a_extract_minutes_from_infobits( 636 unsigned char infobits[10]) 637{ 638 int minutes_tens, minutes_units; 639 640 minutes_units = infobits[2] & ROW25_COLUMN2_MINUTES_UNITS; 641 minutes_tens = infobits[3] & ROW25_COLUMN3_MINUTES_TENS; 642 643 return((minutes_tens << 4) | minutes_units); 644} 645 646/* Reads the status bits contained in the first 10 columns of the first line 647 * and extracts the information into info. 648 * 649 * Return value: 0 if successful 650 */ 651static inline int saa5246a_get_status(struct saa5246a_device *t, 652 vtx_pageinfo_t *info, unsigned char dau_no) 653{ 654 unsigned char infobits[10]; 655 int column; 656 657 if (dau_no >= NUM_DAUS) 658 return -EINVAL; 659 660 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 661 662 dau_no | 663 R8_DO_NOT_CLEAR_MEMORY, 664 665 R9_CURSER_ROW_25, 666 667 R10_CURSER_COLUMN_0, 668 669 COMMAND_END) || 670 i2c_getdata(t, 10, infobits)) 671 { 672 return -EIO; 673 } 674 675 info->pagenum = saa5246a_extract_pagenum_from_infobits(infobits); 676 info->hour = saa5246a_extract_hour_from_infobits(infobits); 677 info->minute = saa5246a_extract_minutes_from_infobits(infobits); 678 info->charset = ((infobits[7] & ROW25_COLUMN7_CHARACTER_SET) >> 1); 679 info->delete = !!(infobits[3] & ROW25_COLUMN3_DELETE_PAGE); 680 info->headline = !!(infobits[5] & ROW25_COLUMN5_INSERT_HEADLINE); 681 info->subtitle = !!(infobits[5] & ROW25_COLUMN5_INSERT_SUBTITLE); 682 info->supp_header = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_HEADER); 683 info->update = !!(infobits[6] & ROW25_COLUMN6_UPDATE_PAGE); 684 info->inter_seq = !!(infobits[6] & ROW25_COLUMN6_INTERRUPTED_SEQUENCE); 685 info->dis_disp = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_DISPLAY); 686 info->serial = !!(infobits[7] & ROW25_COLUMN7_SERIAL_MODE); 687 info->notfound = !!(infobits[8] & ROW25_COLUMN8_PAGE_NOT_FOUND); 688 info->pblf = !!(infobits[9] & ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR); 689 info->hamming = 0; 690 for (column = 0; column <= 7; column++) { 691 if (infobits[column] & ROW25_COLUMN0_TO_7_HAMMING_ERROR) { 692 info->hamming = 1; 693 break; 694 } 695 } 696 if (!info->hamming && !info->notfound) 697 t->is_searching[dau_no] = false; 698 return 0; 699} 700 701/* Reads 1 videotext page buffer of the SAA5246A. 702 * 703 * req is used both as input and as output. It contains information which part 704 * must be read. The videotext page is copied into req->buffer. 705 * 706 * Return value: 0 if successful 707 */ 708static inline int saa5246a_get_page(struct saa5246a_device *t, 709 vtx_pagereq_t *req) 710{ 711 int start, end, size; 712 char *buf; 713 int err; 714 715 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || 716 req->start < 0 || req->start > req->end || req->end >= VTX_PAGESIZE) 717 return -EINVAL; 718 719 buf = kmalloc(VTX_PAGESIZE, GFP_KERNEL); 720 if (!buf) 721 return -ENOMEM; 722 723 /* Read "normal" part of page */ 724 err = -EIO; 725 726 end = min(req->end, VTX_PAGESIZE - 1); 727 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 728 req->pgbuf | R8_DO_NOT_CLEAR_MEMORY, 729 ROW(req->start), COLUMN(req->start), COMMAND_END)) 730 goto out; 731 if (i2c_getdata(t, end - req->start + 1, buf)) 732 goto out; 733 err = -EFAULT; 734 if (copy_to_user(req->buffer, buf, end - req->start + 1)) 735 goto out; 736 737 /* Always get the time from buffer 4, since this stupid SAA5246A only 738 * updates the currently displayed buffer... 739 */ 740 if (REQ_CONTAINS_TIME(req)) { 741 start = max(req->start, POS_TIME_START); 742 end = min(req->end, POS_TIME_END); 743 size = end - start + 1; 744 err = -EINVAL; 745 if (size < 0) 746 goto out; 747 err = -EIO; 748 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 749 R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY, 750 R9_CURSER_ROW_0, start, COMMAND_END)) 751 goto out; 752 if (i2c_getdata(t, size, buf)) 753 goto out; 754 err = -EFAULT; 755 if (copy_to_user(req->buffer + start - req->start, buf, size)) 756 goto out; 757 } 758 /* Insert the header from buffer 4 only, if acquisition circuit is still searching for a page */ 759 if (REQ_CONTAINS_HEADER(req) && t->is_searching[req->pgbuf]) { 760 start = max(req->start, POS_HEADER_START); 761 end = min(req->end, POS_HEADER_END); 762 size = end - start + 1; 763 err = -EINVAL; 764 if (size < 0) 765 goto out; 766 err = -EIO; 767 if (i2c_senddata(t, SAA5246A_REGISTER_R8, 768 R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY, 769 R9_CURSER_ROW_0, start, COMMAND_END)) 770 goto out; 771 if (i2c_getdata(t, end - start + 1, buf)) 772 goto out; 773 err = -EFAULT; 774 if (copy_to_user(req->buffer + start - req->start, buf, size)) 775 goto out; 776 } 777 err = 0; 778out: 779 kfree(buf); 780 return err; 781} 782 783/* Stops the acquisition circuit given in dau_no. The page buffer associated 784 * with this acquisition circuit will no more be updated. The other daus are 785 * not affected. 786 * 787 * Return value: 0 if successful 788 */ 789static inline int saa5246a_stop_dau(struct saa5246a_device *t, 790 unsigned char dau_no) 791{ 792 if (dau_no >= NUM_DAUS) 793 return -EINVAL; 794 if (i2c_senddata(t, SAA5246A_REGISTER_R2, 795 796 R2_IN_R3_SELECT_PAGE_HUNDREDS | 797 dau_no << 4 | 798 R2_BANK_0 | 799 R2_HAMMING_CHECK_OFF, 800 801 R3_PAGE_HUNDREDS_0 | 802 R3_HOLD_PAGE | 803 R3_PAGE_HUNDREDS_DO_NOT_CARE, 804 805 COMMAND_END)) 806 { 807 return -EIO; 808 } 809 t->is_searching[dau_no] = false; 810 return 0; 811} 812 813/* Handles ioctls defined in videotext.h 814 * 815 * Returns 0 if successful 816 */ 817static long do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg) 818{ 819 struct saa5246a_device *t = video_drvdata(file); 820 821 switch(cmd) 822 { 823 case VTXIOCGETINFO: 824 { 825 vtx_info_t *info = arg; 826 827 info->version_major = MAJOR_VERSION; 828 info->version_minor = MINOR_VERSION; 829 info->numpages = NUM_DAUS; 830 return 0; 831 } 832 833 case VTXIOCCLRPAGE: 834 { 835 vtx_pagereq_t *req = arg; 836 837 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS) 838 return -EINVAL; 839 memset(t->pgbuf[req->pgbuf], ' ', sizeof(t->pgbuf[0])); 840 return 0; 841 } 842 843 case VTXIOCCLRFOUND: 844 { 845 vtx_pagereq_t *req = arg; 846 847 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS) 848 return -EINVAL; 849 return(saa5246a_clear_found_bit(t, req->pgbuf)); 850 } 851 852 case VTXIOCPAGEREQ: 853 { 854 vtx_pagereq_t *req = arg; 855 856 return(saa5246a_request_page(t, req)); 857 } 858 859 case VTXIOCGETSTAT: 860 { 861 vtx_pagereq_t *req = arg; 862 vtx_pageinfo_t info; 863 int rval; 864 865 if ((rval = saa5246a_get_status(t, &info, req->pgbuf))) 866 return rval; 867 if(copy_to_user(req->buffer, &info, 868 sizeof(vtx_pageinfo_t))) 869 return -EFAULT; 870 return 0; 871 } 872 873 case VTXIOCGETPAGE: 874 { 875 vtx_pagereq_t *req = arg; 876 877 return(saa5246a_get_page(t, req)); 878 } 879 880 case VTXIOCSTOPDAU: 881 { 882 vtx_pagereq_t *req = arg; 883 884 return(saa5246a_stop_dau(t, req->pgbuf)); 885 } 886 887 case VTXIOCPUTPAGE: 888 case VTXIOCSETDISP: 889 case VTXIOCPUTSTAT: 890 return 0; 891 892 case VTXIOCCLRCACHE: 893 { 894 return 0; 895 } 896 897 case VTXIOCSETVIRT: 898 { 899 /* I do not know what "virtual mode" means */ 900 return 0; 901 } 902 } 903 return -EINVAL; 904} 905 906/* 907 * Translates old vtx IOCTLs to new ones 908 * 909 * This keeps new kernel versions compatible with old userspace programs. 910 */ 911static inline unsigned int vtx_fix_command(unsigned int cmd) 912{ 913 switch (cmd) { 914 case VTXIOCGETINFO_OLD: 915 cmd = VTXIOCGETINFO; 916 break; 917 case VTXIOCCLRPAGE_OLD: 918 cmd = VTXIOCCLRPAGE; 919 break; 920 case VTXIOCCLRFOUND_OLD: 921 cmd = VTXIOCCLRFOUND; 922 break; 923 case VTXIOCPAGEREQ_OLD: 924 cmd = VTXIOCPAGEREQ; 925 break; 926 case VTXIOCGETSTAT_OLD: 927 cmd = VTXIOCGETSTAT; 928 break; 929 case VTXIOCGETPAGE_OLD: 930 cmd = VTXIOCGETPAGE; 931 break; 932 case VTXIOCSTOPDAU_OLD: 933 cmd = VTXIOCSTOPDAU; 934 break; 935 case VTXIOCPUTPAGE_OLD: 936 cmd = VTXIOCPUTPAGE; 937 break; 938 case VTXIOCSETDISP_OLD: 939 cmd = VTXIOCSETDISP; 940 break; 941 case VTXIOCPUTSTAT_OLD: 942 cmd = VTXIOCPUTSTAT; 943 break; 944 case VTXIOCCLRCACHE_OLD: 945 cmd = VTXIOCCLRCACHE; 946 break; 947 case VTXIOCSETVIRT_OLD: 948 cmd = VTXIOCSETVIRT; 949 break; 950 } 951 return cmd; 952} 953 954/* 955 * Handle the locking 956 */ 957static long saa5246a_ioctl(struct file *file, 958 unsigned int cmd, unsigned long arg) 959{ 960 struct saa5246a_device *t = video_drvdata(file); 961 long err; 962 963 cmd = vtx_fix_command(cmd); 964 mutex_lock(&t->lock); 965 err = video_usercopy(file, cmd, arg, do_saa5246a_ioctl); 966 mutex_unlock(&t->lock); 967 return err; 968} 969 970static int saa5246a_open(struct file *file) 971{ 972 struct saa5246a_device *t = video_drvdata(file); 973 974 if (test_and_set_bit(0, &t->in_use)) 975 return -EBUSY; 976 977 if (i2c_senddata(t, SAA5246A_REGISTER_R0, 978 R0_SELECT_R11 | 979 R0_PLL_TIME_CONSTANT_LONG | 980 R0_ENABLE_nODD_EVEN_OUTPUT | 981 R0_ENABLE_HDR_POLL | 982 R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED | 983 R0_NO_FREE_RUN_PLL | 984 R0_NO_AUTOMATIC_FASTEXT_PROMPT, 985 986 R1_NON_INTERLACED_312_312_LINES | 987 R1_DEW | 988 R1_EXTENDED_PACKET_DISABLE | 989 R1_DAUS_ALL_ON | 990 R1_8_BITS_NO_PARITY | 991 R1_VCS_TO_SCS, 992 993 COMMAND_END) || 994 i2c_senddata(t, SAA5246A_REGISTER_R4, 995 996 /* We do not care much for the TV display but nevertheless we 997 * need the currently displayed page later because only on that 998 * page the time is updated. */ 999 R4_DISPLAY_PAGE_4, 1000 1001 COMMAND_END)) 1002 { 1003 clear_bit(0, &t->in_use); 1004 return -EIO; 1005 } 1006 return 0; 1007} 1008 1009static int saa5246a_release(struct file *file) 1010{ 1011 struct saa5246a_device *t = video_drvdata(file); 1012 1013 /* Stop all acquisition circuits. */ 1014 i2c_senddata(t, SAA5246A_REGISTER_R1, 1015 1016 R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES | 1017 R1_DEW | 1018 R1_EXTENDED_PACKET_DISABLE | 1019 R1_DAUS_ALL_OFF | 1020 R1_8_BITS_NO_PARITY | 1021 R1_VCS_TO_SCS, 1022 1023 COMMAND_END); 1024 clear_bit(0, &t->in_use); 1025 return 0; 1026} 1027 1028static const struct v4l2_file_operations saa_fops = { 1029 .owner = THIS_MODULE, 1030 .open = saa5246a_open, 1031 .release = saa5246a_release, 1032 .ioctl = saa5246a_ioctl, 1033}; 1034 1035static struct video_device saa_template = 1036{ 1037 .name = "saa5246a", 1038 .fops = &saa_fops, 1039 .release = video_device_release, 1040}; 1041 1042static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) 1043{ 1044 struct i2c_client *client = v4l2_get_subdevdata(sd); 1045 1046 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0); 1047} 1048 1049static const struct v4l2_subdev_core_ops saa5246a_core_ops = { 1050 .g_chip_ident = saa5246a_g_chip_ident, 1051}; 1052 1053static const struct v4l2_subdev_ops saa5246a_ops = { 1054 .core = &saa5246a_core_ops, 1055}; 1056 1057 1058static int saa5246a_probe(struct i2c_client *client, 1059 const struct i2c_device_id *id) 1060{ 1061 int pgbuf; 1062 int err; 1063 struct saa5246a_device *t; 1064 struct v4l2_subdev *sd; 1065 1066 v4l_info(client, "chip found @ 0x%x (%s)\n", 1067 client->addr << 1, client->adapter->name); 1068 v4l_info(client, "VideoText version %d.%d\n", 1069 MAJOR_VERSION, MINOR_VERSION); 1070 t = kzalloc(sizeof(*t), GFP_KERNEL); 1071 if (t == NULL) 1072 return -ENOMEM; 1073 sd = &t->sd; 1074 v4l2_i2c_subdev_init(sd, client, &saa5246a_ops); 1075 mutex_init(&t->lock); 1076 1077 /* Now create a video4linux device */ 1078 t->vdev = video_device_alloc(); 1079 if (t->vdev == NULL) { 1080 kfree(t); 1081 return -ENOMEM; 1082 } 1083 memcpy(t->vdev, &saa_template, sizeof(*t->vdev)); 1084 1085 for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { 1086 memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0])); 1087 t->is_searching[pgbuf] = false; 1088 } 1089 video_set_drvdata(t->vdev, t); 1090 1091 /* Register it */ 1092 err = video_register_device(t->vdev, VFL_TYPE_VTX, -1); 1093 if (err < 0) { 1094 video_device_release(t->vdev); 1095 kfree(t); 1096 return err; 1097 } 1098 return 0; 1099} 1100 1101static int saa5246a_remove(struct i2c_client *client) 1102{ 1103 struct v4l2_subdev *sd = i2c_get_clientdata(client); 1104 struct saa5246a_device *t = to_dev(sd); 1105 1106 video_unregister_device(t->vdev); 1107 v4l2_device_unregister_subdev(sd); 1108 kfree(t); 1109 return 0; 1110} 1111 1112static const struct i2c_device_id saa5246a_id[] = { 1113 { "saa5246a", 0 }, 1114 { } 1115}; 1116MODULE_DEVICE_TABLE(i2c, saa5246a_id); 1117 1118static struct v4l2_i2c_driver_data v4l2_i2c_data = { 1119 .name = "saa5246a", 1120 .probe = saa5246a_probe, 1121 .remove = saa5246a_remove, 1122 .id_table = saa5246a_id, 1123}; 1124