aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2010-08-06 10:08:54 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-20 23:05:48 -0400
commit563711f16f5d5ee8b639a3d6ee4cef199617009c (patch)
treecacb087acb40d3eadb9bf65881cef734e6f611b0 /drivers
parentbe96624a38e6de619603b5741a39e715eb44227c (diff)
V4L/DVB: saa5246a/saa5249: Remove obsolete teletext drivers
These old i2c teletext drivers are not supported by any hardware and cannot be tested anymore. Note that while the mxb board seemingly used the saa5246a driver, in reality this teletext driver never worked. These drivers are removed as part of the vtx feature removal, originally scheduled for 2.6.35. 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/Kconfig20
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/mxb.c5
-rw-r--r--drivers/media/video/saa5246a.c1123
-rw-r--r--drivers/media/video/saa5249.c650
5 files changed, 0 insertions, 1800 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f6e4d0475351..2c0a8f776f8a 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -641,26 +641,6 @@ config VIDEO_CPIA_USB
641 641
642source "drivers/media/video/cpia2/Kconfig" 642source "drivers/media/video/cpia2/Kconfig"
643 643
644config VIDEO_SAA5246A
645 tristate "SAA5246A, SAA5281 Teletext processor"
646 depends on I2C && VIDEO_V4L2
647 help
648 Support for I2C bus based teletext using the SAA5246A or SAA5281
649 chip. Useful only if you live in Europe.
650
651 To compile this driver as a module, choose M here: the
652 module will be called saa5246a.
653
654config VIDEO_SAA5249
655 tristate "SAA5249 Teletext processor"
656 depends on I2C && VIDEO_V4L2
657 help
658 Support for I2C bus based teletext using the SAA5249 chip. At the
659 moment this is only useful on some European WinTV cards.
660
661 To compile this driver as a module, choose M here: the
662 module will be called saa5249.
663
664config VIDEO_VINO 644config VIDEO_VINO
665 tristate "SGI Vino Video For Linux (EXPERIMENTAL)" 645 tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
666 depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 646 depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 40f98fba5f88..a8f89899dd6b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -33,8 +33,6 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
33obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o 33obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
34obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o 34obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
35obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o 35obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
36obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
37obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
38obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o 36obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
39obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o 37obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
40obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o 38obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index ef0c8178f255..da07d14ec8df 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -32,7 +32,6 @@
32#include "tea6415c.h" 32#include "tea6415c.h"
33#include "tea6420.h" 33#include "tea6420.h"
34 34
35#define I2C_SAA5246A 0x11
36#define I2C_SAA7111A 0x24 35#define I2C_SAA7111A 0x24
37#define I2C_TDA9840 0x42 36#define I2C_TDA9840 0x42
38#define I2C_TEA6415C 0x43 37#define I2C_TEA6415C 0x43
@@ -197,10 +196,6 @@ static int mxb_probe(struct saa7146_dev *dev)
197 "tda9840", "tda9840", I2C_TDA9840, NULL); 196 "tda9840", "tda9840", I2C_TDA9840, NULL);
198 mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, 197 mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
199 "tuner", "tuner", I2C_TUNER, NULL); 198 "tuner", "tuner", I2C_TUNER, NULL);
200 if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
201 "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
202 printk(KERN_INFO "mxb: found teletext decoder\n");
203 }
204 199
205 /* check if all devices are present */ 200 /* check if all devices are present */
206 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || 201 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
deleted file mode 100644
index 6b3b09ef8978..000000000000
--- a/drivers/media/video/saa5246a.c
+++ /dev/null
@@ -1,1123 +0,0 @@
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};
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
deleted file mode 100644
index 31ff27df4cbf..000000000000
--- a/drivers/media/video/saa5249.c
+++ /dev/null
@@ -1,650 +0,0 @@
1/*
2 * Modified in order to keep it compatible both with new and old videotext IOCTLs by
3 * Michael Geng <linux@MichaelGeng.de>
4 *
5 * Cleaned up to use existing videodev interface and allow the idea
6 * of multiple teletext decoders on the video4linux iface. Changed i2c
7 * to cover addressing clashes on device busses. It's also rebuilt so
8 * you can add arbitary multiple teletext devices to Linux video4linux
9 * now (well 32 anyway).
10 *
11 * Alan Cox <alan@lxorguk.ukuu.org.uk>
12 *
13 * The original driver was heavily modified to match the i2c interface
14 * It was truncated to use the WinTV boards, too.
15 *
16 * Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
17 *
18 * Derived From
19 *
20 * vtx.c:
21 * This is a loadable character-device-driver for videotext-interfaces
22 * (aka teletext). Please check the Makefile/README for a list of supported
23 * interfaces.
24 *
25 * Copyright (c) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de>
26 *
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
41 * USA.
42 */
43
44#include <linux/module.h>
45#include <linux/kernel.h>
46#include <linux/mm.h>
47#include <linux/init.h>
48#include <linux/i2c.h>
49#include <linux/mutex.h>
50#include <linux/delay.h>
51#include <linux/videotext.h>
52#include <linux/videodev2.h>
53#include <linux/slab.h>
54#include <media/v4l2-device.h>
55#include <media/v4l2-chip-ident.h>
56#include <media/v4l2-ioctl.h>
57#include <media/v4l2-i2c-drv.h>
58
59MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
60MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
61MODULE_LICENSE("GPL");
62
63
64#define VTX_VER_MAJ 1
65#define VTX_VER_MIN 8
66
67
68#define NUM_DAUS 4
69#define NUM_BUFS 8
70
71static const int disp_modes[8][3] =
72{
73 { 0x46, 0x03, 0x03 }, /* DISPOFF */
74 { 0x46, 0xcc, 0xcc }, /* DISPNORM */
75 { 0x44, 0x0f, 0x0f }, /* DISPTRANS */
76 { 0x46, 0xcc, 0x46 }, /* DISPINS */
77 { 0x44, 0x03, 0x03 }, /* DISPOFF, interlaced */
78 { 0x44, 0xcc, 0xcc }, /* DISPNORM, interlaced */
79 { 0x44, 0x0f, 0x0f }, /* DISPTRANS, interlaced */
80 { 0x44, 0xcc, 0x46 } /* DISPINS, interlaced */
81};
82
83
84
85#define PAGE_WAIT msecs_to_jiffies(300) /* Time between requesting page and */
86 /* checking status bits */
87#define PGBUF_EXPIRE msecs_to_jiffies(15000) /* Time to wait before retransmitting */
88 /* page regardless of infobits */
89typedef struct {
90 u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
91 u8 laststat[10]; /* Last value of infobits for DAU */
92 u8 sregs[7]; /* Page-request registers */
93 unsigned long expire; /* Time when page will be expired */
94 unsigned clrfound : 1; /* VTXIOCCLRFOUND has been called */
95 unsigned stopped : 1; /* VTXIOCSTOPDAU has been called */
96} vdau_t;
97
98struct saa5249_device
99{
100 struct v4l2_subdev sd;
101 struct video_device *vdev;
102 vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */
103 /* real DAU, so we have to simulate some more) */
104 int vtx_use_count;
105 int is_searching[NUM_DAUS];
106 int disp_mode;
107 int virtual_mode;
108 unsigned long in_use;
109 struct mutex lock;
110};
111
112static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
113{
114 return container_of(sd, struct saa5249_device, sd);
115}
116
117
118#define CCTWR 34 /* I²C write/read-address of vtx-chip */
119#define CCTRD 35
120#define NOACK_REPEAT 10 /* Retry access this many times on failure */
121#define CLEAR_DELAY msecs_to_jiffies(50) /* Time required to clear a page */
122#define READY_TIMEOUT msecs_to_jiffies(30) /* Time to wait for ready signal of I2C-bus interface */
123#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
124#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
125
126#define VTX_DEV_MINOR 0
127
128static struct video_device saa_template; /* Declared near bottom */
129
130/*
131 * Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
132 * delay may be longer.
133 */
134
135static void jdelay(unsigned long delay)
136{
137 sigset_t oldblocked = current->blocked;
138
139 spin_lock_irq(&current->sighand->siglock);
140 sigfillset(&current->blocked);
141 recalc_sigpending();
142 spin_unlock_irq(&current->sighand->siglock);
143 msleep_interruptible(jiffies_to_msecs(delay));
144
145 spin_lock_irq(&current->sighand->siglock);
146 current->blocked = oldblocked;
147 recalc_sigpending();
148 spin_unlock_irq(&current->sighand->siglock);
149}
150
151
152/*
153 * I2C interfaces
154 */
155
156static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
157{
158 struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
159 char buf[64];
160
161 buf[0] = reg;
162 memcpy(buf+1, data, count);
163
164 if (i2c_master_send(client, buf, count + 1) == count + 1)
165 return 0;
166 return -1;
167}
168
169static int i2c_senddata(struct saa5249_device *t, ...)
170{
171 unsigned char buf[64];
172 int v;
173 int ct = 0;
174 va_list argp;
175 va_start(argp,t);
176
177 while ((v = va_arg(argp, int)) != -1)
178 buf[ct++] = v;
179
180 va_end(argp);
181 return i2c_sendbuf(t, buf[0], ct-1, buf+1);
182}
183
184/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
185 * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
186 * sending of data. If uaccess is 'true', data is written to user-space with put_user.
187 * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
188 */
189
190static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
191{
192 struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
193
194 if (i2c_master_recv(client, buf, count) != count)
195 return -1;
196 return 0;
197}
198
199
200/*
201 * Standard character-device-driver functions
202 */
203
204static long do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
205{
206 static int virtual_mode = false;
207 struct saa5249_device *t = video_drvdata(file);
208
209 switch (cmd) {
210 case VTXIOCGETINFO:
211 {
212 vtx_info_t *info = arg;
213 info->version_major = VTX_VER_MAJ;
214 info->version_minor = VTX_VER_MIN;
215 info->numpages = NUM_DAUS;
216 /*info->cct_type = CCT_TYPE;*/
217 return 0;
218 }
219
220 case VTXIOCCLRPAGE:
221 {
222 vtx_pagereq_t *req = arg;
223
224 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
225 return -EINVAL;
226 memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
227 t->vdau[req->pgbuf].clrfound = true;
228 return 0;
229 }
230
231 case VTXIOCCLRFOUND:
232 {
233 vtx_pagereq_t *req = arg;
234
235 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
236 return -EINVAL;
237 t->vdau[req->pgbuf].clrfound = true;
238 return 0;
239 }
240
241 case VTXIOCPAGEREQ:
242 {
243 vtx_pagereq_t *req = arg;
244 if (!(req->pagemask & PGMASK_PAGE))
245 req->page = 0;
246 if (!(req->pagemask & PGMASK_HOUR))
247 req->hour = 0;
248 if (!(req->pagemask & PGMASK_MINUTE))
249 req->minute = 0;
250 if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
251 return -EINVAL;
252 req->page &= 0x7ff;
253 if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
254 req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
255 return -EINVAL;
256 t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
257 t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
258 t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
259 t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
260 t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
261 t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
262 t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
263 t->vdau[req->pgbuf].stopped = false;
264 t->vdau[req->pgbuf].clrfound = true;
265 t->is_searching[req->pgbuf] = true;
266 return 0;
267 }
268
269 case VTXIOCGETSTAT:
270 {
271 vtx_pagereq_t *req = arg;
272 u8 infobits[10];
273 vtx_pageinfo_t info;
274 int a;
275
276 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
277 return -EINVAL;
278 if (!t->vdau[req->pgbuf].stopped) {
279 if (i2c_senddata(t, 2, 0, -1) ||
280 i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
281 i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
282 i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
283 i2c_senddata(t, 8, 0, 25, 0, -1))
284 return -EIO;
285 jdelay(PAGE_WAIT);
286 if (i2c_getdata(t, 10, infobits))
287 return -EIO;
288
289 if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) && /* check FOUND-bit */
290 (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
291 time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
292 { /* check if new page arrived */
293 if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
294 i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
295 return -EIO;
296 t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
297 memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
298 if (t->virtual_mode) {
299 /* Packet X/24 */
300 if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
301 i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
302 return -EIO;
303 /* Packet X/27/0 */
304 if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
305 i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
306 return -EIO;
307 /* Packet 8/30/0...8/30/15
308 * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
309 * so we should undo this here.
310 */
311 if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
312 i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
313 return -EIO;
314 }
315 t->vdau[req->pgbuf].clrfound = false;
316 memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
317 } else {
318 memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
319 }
320 } else {
321 memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
322 }
323
324 info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
325 if (info.pagenum < 0x100)
326 info.pagenum += 0x800;
327 info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
328 info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
329 info.charset = ((infobits[7] >> 1) & 7);
330 info.delete = !!(infobits[3] & 8);
331 info.headline = !!(infobits[5] & 4);
332 info.subtitle = !!(infobits[5] & 8);
333 info.supp_header = !!(infobits[6] & 1);
334 info.update = !!(infobits[6] & 2);
335 info.inter_seq = !!(infobits[6] & 4);
336 info.dis_disp = !!(infobits[6] & 8);
337 info.serial = !!(infobits[7] & 1);
338 info.notfound = !!(infobits[8] & 0x10);
339 info.pblf = !!(infobits[9] & 0x20);
340 info.hamming = 0;
341 for (a = 0; a <= 7; a++) {
342 if (infobits[a] & 0xf0) {
343 info.hamming = 1;
344 break;
345 }
346 }
347 if (t->vdau[req->pgbuf].clrfound)
348 info.notfound = 1;
349 if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
350 return -EFAULT;
351 if (!info.hamming && !info.notfound)
352 t->is_searching[req->pgbuf] = false;
353 return 0;
354 }
355
356 case VTXIOCGETPAGE:
357 {
358 vtx_pagereq_t *req = arg;
359 int start, end;
360
361 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
362 req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
363 return -EINVAL;
364 if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
365 return -EFAULT;
366
367 /*
368 * Always read the time directly from SAA5249
369 */
370
371 if (req->start <= 39 && req->end >= 32) {
372 int len;
373 char buf[16];
374 start = max(req->start, 32);
375 end = min(req->end, 39);
376 len = end - start + 1;
377 if (i2c_senddata(t, 8, 0, 0, start, -1) ||
378 i2c_getdata(t, len, buf))
379 return -EIO;
380 if (copy_to_user(req->buffer + start - req->start, buf, len))
381 return -EFAULT;
382 }
383 /* Insert the current header if DAU is still searching for a page */
384 if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
385 char buf[32];
386 int len;
387
388 start = max(req->start, 7);
389 end = min(req->end, 31);
390 len = end - start + 1;
391 if (i2c_senddata(t, 8, 0, 0, start, -1) ||
392 i2c_getdata(t, len, buf))
393 return -EIO;
394 if (copy_to_user(req->buffer + start - req->start, buf, len))
395 return -EFAULT;
396 }
397 return 0;
398 }
399
400 case VTXIOCSTOPDAU:
401 {
402 vtx_pagereq_t *req = arg;
403
404 if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
405 return -EINVAL;
406 t->vdau[req->pgbuf].stopped = true;
407 t->is_searching[req->pgbuf] = false;
408 return 0;
409 }
410
411 case VTXIOCPUTPAGE:
412 case VTXIOCSETDISP:
413 case VTXIOCPUTSTAT:
414 return 0;
415
416 case VTXIOCCLRCACHE:
417 {
418 if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
419 ' ', ' ', ' ', ' ', ' ', ' ',
420 ' ', ' ', ' ', ' ', ' ', ' ',
421 ' ', ' ', ' ', ' ', ' ', ' ',
422 ' ', ' ', ' ', ' ', ' ', ' ',
423 -1))
424 return -EIO;
425 if (i2c_senddata(t, 3, 0x20, -1))
426 return -EIO;
427 jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */
428 return 0;
429 }
430
431 case VTXIOCSETVIRT:
432 {
433 /* The SAA5249 has virtual-row reception turned on always */
434 t->virtual_mode = (int)(long)arg;
435 return 0;
436 }
437 }
438 return -EINVAL;
439}
440
441/*
442 * Translates old vtx IOCTLs to new ones
443 *
444 * This keeps new kernel versions compatible with old userspace programs.
445 */
446static inline unsigned int vtx_fix_command(unsigned int cmd)
447{
448 switch (cmd) {
449 case VTXIOCGETINFO_OLD:
450 cmd = VTXIOCGETINFO;
451 break;
452 case VTXIOCCLRPAGE_OLD:
453 cmd = VTXIOCCLRPAGE;
454 break;
455 case VTXIOCCLRFOUND_OLD:
456 cmd = VTXIOCCLRFOUND;
457 break;
458 case VTXIOCPAGEREQ_OLD:
459 cmd = VTXIOCPAGEREQ;
460 break;
461 case VTXIOCGETSTAT_OLD:
462 cmd = VTXIOCGETSTAT;
463 break;
464 case VTXIOCGETPAGE_OLD:
465 cmd = VTXIOCGETPAGE;
466 break;
467 case VTXIOCSTOPDAU_OLD:
468 cmd = VTXIOCSTOPDAU;
469 break;
470 case VTXIOCPUTPAGE_OLD:
471 cmd = VTXIOCPUTPAGE;
472 break;
473 case VTXIOCSETDISP_OLD:
474 cmd = VTXIOCSETDISP;
475 break;
476 case VTXIOCPUTSTAT_OLD:
477 cmd = VTXIOCPUTSTAT;
478 break;
479 case VTXIOCCLRCACHE_OLD:
480 cmd = VTXIOCCLRCACHE;
481 break;
482 case VTXIOCSETVIRT_OLD:
483 cmd = VTXIOCSETVIRT;
484 break;
485 }
486 return cmd;
487}
488
489/*
490 * Handle the locking
491 */
492
493static long saa5249_ioctl(struct file *file,
494 unsigned int cmd, unsigned long arg)
495{
496 struct saa5249_device *t = video_drvdata(file);
497 long err;
498
499 cmd = vtx_fix_command(cmd);
500 mutex_lock(&t->lock);
501 err = video_usercopy(file, cmd, arg, do_saa5249_ioctl);
502 mutex_unlock(&t->lock);
503 return err;
504}
505
506static int saa5249_open(struct file *file)
507{
508 struct saa5249_device *t = video_drvdata(file);
509 int pgbuf;
510
511 if (test_and_set_bit(0, &t->in_use))
512 return -EBUSY;
513
514 if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
515 /* Turn off parity checks (we do this ourselves) */
516 i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
517 /* Display TV-picture, no virtual rows */
518 i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
519 /* Set display to page 4 */
520 {
521 clear_bit(0, &t->in_use);
522 return -EIO;
523 }
524
525 for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
526 memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
527 memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
528 memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
529 t->vdau[pgbuf].expire = 0;
530 t->vdau[pgbuf].clrfound = true;
531 t->vdau[pgbuf].stopped = true;
532 t->is_searching[pgbuf] = false;
533 }
534 t->virtual_mode = false;
535 return 0;
536}
537
538
539
540static int saa5249_release(struct file *file)
541{
542 struct saa5249_device *t = video_drvdata(file);
543
544 i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */
545 i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */
546 clear_bit(0, &t->in_use);
547 return 0;
548}
549
550static const struct v4l2_file_operations saa_fops = {
551 .owner = THIS_MODULE,
552 .open = saa5249_open,
553 .release = saa5249_release,
554 .ioctl = saa5249_ioctl,
555};
556
557static struct video_device saa_template =
558{
559 .name = "saa5249",
560 .fops = &saa_fops,
561 .release = video_device_release,
562};
563
564static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
565{
566 struct i2c_client *client = v4l2_get_subdevdata(sd);
567
568 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
569}
570
571static const struct v4l2_subdev_core_ops saa5249_core_ops = {
572 .g_chip_ident = saa5249_g_chip_ident,
573};
574
575static const struct v4l2_subdev_ops saa5249_ops = {
576 .core = &saa5249_core_ops,
577};
578
579static int saa5249_probe(struct i2c_client *client,
580 const struct i2c_device_id *id)
581{
582 int pgbuf;
583 int err;
584 struct saa5249_device *t;
585 struct v4l2_subdev *sd;
586
587 v4l_info(client, "chip found @ 0x%x (%s)\n",
588 client->addr << 1, client->adapter->name);
589 v4l_info(client, "VideoText version %d.%d\n",
590 VTX_VER_MAJ, VTX_VER_MIN);
591 t = kzalloc(sizeof(*t), GFP_KERNEL);
592 if (t == NULL)
593 return -ENOMEM;
594 sd = &t->sd;
595 v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
596 mutex_init(&t->lock);
597
598 /* Now create a video4linux device */
599 t->vdev = video_device_alloc();
600 if (t->vdev == NULL) {
601 kfree(t);
602 kfree(client);
603 return -ENOMEM;
604 }
605 memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
606
607 for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
608 memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
609 memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
610 memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
611 t->vdau[pgbuf].expire = 0;
612 t->vdau[pgbuf].clrfound = true;
613 t->vdau[pgbuf].stopped = true;
614 t->is_searching[pgbuf] = false;
615 }
616 video_set_drvdata(t->vdev, t);
617
618 /* Register it */
619 err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
620 if (err < 0) {
621 video_device_release(t->vdev);
622 kfree(t);
623 return err;
624 }
625 return 0;
626}
627
628static int saa5249_remove(struct i2c_client *client)
629{
630 struct v4l2_subdev *sd = i2c_get_clientdata(client);
631 struct saa5249_device *t = to_dev(sd);
632
633 video_unregister_device(t->vdev);
634 v4l2_device_unregister_subdev(sd);
635 kfree(t);
636 return 0;
637}
638
639static const struct i2c_device_id saa5249_id[] = {
640 { "saa5249", 0 },
641 { }
642};
643MODULE_DEVICE_TABLE(i2c, saa5249_id);
644
645static struct v4l2_i2c_driver_data v4l2_i2c_data = {
646 .name = "saa5249",
647 .probe = saa5249_probe,
648 .remove = saa5249_remove,
649 .id_table = saa5249_id,
650};