diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-09-07 07:31:13 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-12 07:37:00 -0400 |
commit | 71ef85c7e0f431467c2e18314ff0cb8fa2b84e5f (patch) | |
tree | 2ac85b0311968f97848a11a14fc14e797c216ac0 /drivers/media/video/saa5246a.c | |
parent | 2633812f897cc354071699e86ea82e3bfd77cddc (diff) |
V4L/DVB (8943): saa5246a: convert i2c driver for new i2c API
- Convert to use v4l2-i2c-drv-legacy.h to be able to handle the new i2c API
- Cleanups
- Use v4l_dbg/v4l_info to have uniform kernel messages
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/saa5246a.c')
-rw-r--r-- | drivers/media/video/saa5246a.c | 520 |
1 files changed, 400 insertions, 120 deletions
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index ff81049e936d..4a21b8a6a709 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c | |||
@@ -43,138 +43,363 @@ | |||
43 | #include <linux/mm.h> | 43 | #include <linux/mm.h> |
44 | #include <linux/init.h> | 44 | #include <linux/init.h> |
45 | #include <linux/i2c.h> | 45 | #include <linux/i2c.h> |
46 | #include <linux/videotext.h> | ||
47 | #include <linux/smp_lock.h> | 46 | #include <linux/smp_lock.h> |
47 | #include <linux/mutex.h> | ||
48 | #include <linux/videotext.h> | ||
48 | #include <linux/videodev.h> | 49 | #include <linux/videodev.h> |
49 | #include <media/v4l2-common.h> | 50 | #include <media/v4l2-common.h> |
50 | #include <media/v4l2-ioctl.h> | 51 | #include <media/v4l2-ioctl.h> |
51 | #include <linux/mutex.h> | 52 | #include <media/v4l2-i2c-drv-legacy.h> |
52 | |||
53 | #include "saa5246a.h" | ||
54 | 53 | ||
55 | MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>"); | 54 | MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>"); |
56 | MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver"); | 55 | MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver"); |
57 | MODULE_LICENSE("GPL"); | 56 | MODULE_LICENSE("GPL"); |
58 | 57 | ||
59 | struct saa5246a_device | 58 | #define MAJOR_VERSION 1 /* driver major version number */ |
60 | { | 59 | #define MINOR_VERSION 8 /* driver minor version number */ |
61 | u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE]; | 60 | |
62 | int is_searching[NUM_DAUS]; | 61 | /* Number of DAUs = number of pages that can be searched at the same time. */ |
63 | struct i2c_client *client; | 62 | #define NUM_DAUS 4 |
64 | unsigned long in_use; | 63 | |
65 | struct mutex lock; | 64 | #define NUM_ROWS_PER_PAGE 40 |
66 | }; | 65 | |
66 | /* first column is 0 (not 1) */ | ||
67 | #define POS_TIME_START 32 | ||
68 | #define POS_TIME_END 39 | ||
69 | |||
70 | #define POS_HEADER_START 7 | ||
71 | #define POS_HEADER_END 31 | ||
72 | |||
73 | /* Returns 'true' if the part of the videotext page described with req contains | ||
74 | (at least parts of) the time field */ | ||
75 | #define REQ_CONTAINS_TIME(p_req) \ | ||
76 | ((p_req)->start <= POS_TIME_END && \ | ||
77 | (p_req)->end >= POS_TIME_START) | ||
78 | |||
79 | /* Returns 'true' if the part of the videotext page described with req contains | ||
80 | (at least parts of) the page header */ | ||
81 | #define REQ_CONTAINS_HEADER(p_req) \ | ||
82 | ((p_req)->start <= POS_HEADER_END && \ | ||
83 | (p_req)->end >= POS_HEADER_START) | ||
84 | |||
85 | /*****************************************************************************/ | ||
86 | /* Mode register numbers of the SAA5246A */ | ||
87 | /*****************************************************************************/ | ||
88 | #define SAA5246A_REGISTER_R0 0 | ||
89 | #define SAA5246A_REGISTER_R1 1 | ||
90 | #define SAA5246A_REGISTER_R2 2 | ||
91 | #define SAA5246A_REGISTER_R3 3 | ||
92 | #define SAA5246A_REGISTER_R4 4 | ||
93 | #define SAA5246A_REGISTER_R5 5 | ||
94 | #define SAA5246A_REGISTER_R6 6 | ||
95 | #define SAA5246A_REGISTER_R7 7 | ||
96 | #define SAA5246A_REGISTER_R8 8 | ||
97 | #define SAA5246A_REGISTER_R9 9 | ||
98 | #define SAA5246A_REGISTER_R10 10 | ||
99 | #define SAA5246A_REGISTER_R11 11 | ||
100 | #define SAA5246A_REGISTER_R11B 11 | ||
101 | |||
102 | /* SAA5246A mode registers often autoincrement to the next register. | ||
103 | Therefore we use variable argument lists. The following macro indicates | ||
104 | the end of a command list. */ | ||
105 | #define COMMAND_END (-1) | ||
106 | |||
107 | /*****************************************************************************/ | ||
108 | /* Contents of the mode registers of the SAA5246A */ | ||
109 | /*****************************************************************************/ | ||
110 | /* Register R0 (Advanced Control) */ | ||
111 | #define R0_SELECT_R11 0x00 | ||
112 | #define R0_SELECT_R11B 0x01 | ||
113 | |||
114 | #define R0_PLL_TIME_CONSTANT_LONG 0x00 | ||
115 | #define R0_PLL_TIME_CONSTANT_SHORT 0x02 | ||
116 | |||
117 | #define R0_ENABLE_nODD_EVEN_OUTPUT 0x00 | ||
118 | #define R0_DISABLE_nODD_EVEN_OUTPUT 0x04 | ||
119 | |||
120 | #define R0_ENABLE_HDR_POLL 0x00 | ||
121 | #define R0_DISABLE_HDR_POLL 0x10 | ||
122 | |||
123 | #define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00 | ||
124 | #define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x20 | ||
125 | |||
126 | #define R0_NO_FREE_RUN_PLL 0x00 | ||
127 | #define R0_FREE_RUN_PLL 0x40 | ||
128 | |||
129 | #define R0_NO_AUTOMATIC_FASTEXT_PROMPT 0x00 | ||
130 | #define R0_AUTOMATIC_FASTEXT_PROMPT 0x80 | ||
131 | |||
132 | /* Register R1 (Mode) */ | ||
133 | #define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES 0x00 | ||
134 | #define R1_NON_INTERLACED_312_313_LINES 0x01 | ||
135 | #define R1_NON_INTERLACED_312_312_LINES 0x02 | ||
136 | #define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE 0x03 | ||
137 | #define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE 0x07 | ||
138 | |||
139 | #define R1_DEW 0x00 | ||
140 | #define R1_FULL_FIELD 0x08 | ||
141 | |||
142 | #define R1_EXTENDED_PACKET_DISABLE 0x00 | ||
143 | #define R1_EXTENDED_PACKET_ENABLE 0x10 | ||
144 | |||
145 | #define R1_DAUS_ALL_ON 0x00 | ||
146 | #define R1_DAUS_ALL_OFF 0x20 | ||
147 | |||
148 | #define R1_7_BITS_PLUS_PARITY 0x00 | ||
149 | #define R1_8_BITS_NO_PARITY 0x40 | ||
150 | |||
151 | #define R1_VCS_TO_SCS 0x00 | ||
152 | #define R1_NO_VCS_TO_SCS 0x80 | ||
153 | |||
154 | /* Register R2 (Page request address) */ | ||
155 | #define R2_IN_R3_SELECT_PAGE_HUNDREDS 0x00 | ||
156 | #define R2_IN_R3_SELECT_PAGE_TENS 0x01 | ||
157 | #define R2_IN_R3_SELECT_PAGE_UNITS 0x02 | ||
158 | #define R2_IN_R3_SELECT_HOURS_TENS 0x03 | ||
159 | #define R2_IN_R3_SELECT_HOURS_UNITS 0x04 | ||
160 | #define R2_IN_R3_SELECT_MINUTES_TENS 0x05 | ||
161 | #define R2_IN_R3_SELECT_MINUTES_UNITS 0x06 | ||
162 | |||
163 | #define R2_DAU_0 0x00 | ||
164 | #define R2_DAU_1 0x10 | ||
165 | #define R2_DAU_2 0x20 | ||
166 | #define R2_DAU_3 0x30 | ||
167 | |||
168 | #define R2_BANK_0 0x00 | ||
169 | #define R2_BANK 1 0x40 | ||
170 | |||
171 | #define R2_HAMMING_CHECK_ON 0x80 | ||
172 | #define R2_HAMMING_CHECK_OFF 0x00 | ||
173 | |||
174 | /* Register R3 (Page request data) */ | ||
175 | #define R3_PAGE_HUNDREDS_0 0x00 | ||
176 | #define R3_PAGE_HUNDREDS_1 0x01 | ||
177 | #define R3_PAGE_HUNDREDS_2 0x02 | ||
178 | #define R3_PAGE_HUNDREDS_3 0x03 | ||
179 | #define R3_PAGE_HUNDREDS_4 0x04 | ||
180 | #define R3_PAGE_HUNDREDS_5 0x05 | ||
181 | #define R3_PAGE_HUNDREDS_6 0x06 | ||
182 | #define R3_PAGE_HUNDREDS_7 0x07 | ||
67 | 183 | ||
68 | static struct video_device saa_template; /* Declared near bottom */ | 184 | #define R3_HOLD_PAGE 0x00 |
185 | #define R3_UPDATE_PAGE 0x08 | ||
69 | 186 | ||
70 | /* Addresses to scan */ | 187 | #define R3_PAGE_HUNDREDS_DO_NOT_CARE 0x00 |
71 | static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; | 188 | #define R3_PAGE_HUNDREDS_DO_CARE 0x10 |
72 | 189 | ||
73 | I2C_CLIENT_INSMOD; | 190 | #define R3_PAGE_TENS_DO_NOT_CARE 0x00 |
191 | #define R3_PAGE_TENS_DO_CARE 0x10 | ||
74 | 192 | ||
75 | static struct i2c_client client_template; | 193 | #define R3_PAGE_UNITS_DO_NOT_CARE 0x00 |
194 | #define R3_PAGE_UNITS_DO_CARE 0x10 | ||
76 | 195 | ||
77 | static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind) | 196 | #define R3_HOURS_TENS_DO_NOT_CARE 0x00 |
78 | { | 197 | #define R3_HOURS_TENS_DO_CARE 0x10 |
79 | int pgbuf; | ||
80 | int err; | ||
81 | struct i2c_client *client; | ||
82 | struct video_device *vd; | ||
83 | struct saa5246a_device *t; | ||
84 | 198 | ||
85 | printk(KERN_INFO "saa5246a: teletext chip found.\n"); | 199 | #define R3_HOURS_UNITS_DO_NOT_CARE 0x00 |
86 | client=kmalloc(sizeof(*client), GFP_KERNEL); | 200 | #define R3_HOURS_UNITS_DO_CARE 0x10 |
87 | if(client==NULL) | ||
88 | return -ENOMEM; | ||
89 | client_template.adapter = adap; | ||
90 | client_template.addr = addr; | ||
91 | memcpy(client, &client_template, sizeof(*client)); | ||
92 | t = kzalloc(sizeof(*t), GFP_KERNEL); | ||
93 | if(t==NULL) | ||
94 | { | ||
95 | kfree(client); | ||
96 | return -ENOMEM; | ||
97 | } | ||
98 | strlcpy(client->name, IF_NAME, I2C_NAME_SIZE); | ||
99 | mutex_init(&t->lock); | ||
100 | 201 | ||
101 | /* | 202 | #define R3_MINUTES_TENS_DO_NOT_CARE 0x00 |
102 | * Now create a video4linux device | 203 | #define R3_MINUTES_TENS_DO_CARE 0x10 |
103 | */ | ||
104 | 204 | ||
105 | vd = video_device_alloc(); | 205 | #define R3_MINUTES_UNITS_DO_NOT_CARE 0x00 |
106 | if(vd==NULL) | 206 | #define R3_MINUTES_UNITS_DO_CARE 0x10 |
107 | { | ||
108 | kfree(t); | ||
109 | kfree(client); | ||
110 | return -ENOMEM; | ||
111 | } | ||
112 | i2c_set_clientdata(client, vd); | ||
113 | memcpy(vd, &saa_template, sizeof(*vd)); | ||
114 | 207 | ||
115 | for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) | 208 | /* Register R4 (Display chapter) */ |
116 | { | 209 | #define R4_DISPLAY_PAGE_0 0x00 |
117 | memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0])); | 210 | #define R4_DISPLAY_PAGE_1 0x01 |
118 | t->is_searching[pgbuf] = false; | 211 | #define R4_DISPLAY_PAGE_2 0x02 |
119 | } | 212 | #define R4_DISPLAY_PAGE_3 0x03 |
120 | video_set_drvdata(vd, t); | 213 | #define R4_DISPLAY_PAGE_4 0x04 |
214 | #define R4_DISPLAY_PAGE_5 0x05 | ||
215 | #define R4_DISPLAY_PAGE_6 0x06 | ||
216 | #define R4_DISPLAY_PAGE_7 0x07 | ||
121 | 217 | ||
218 | /* Register R5 (Normal display control) */ | ||
219 | #define R5_PICTURE_INSIDE_BOXING_OFF 0x00 | ||
220 | #define R5_PICTURE_INSIDE_BOXING_ON 0x01 | ||
122 | 221 | ||
123 | /* | 222 | #define R5_PICTURE_OUTSIDE_BOXING_OFF 0x00 |
124 | * Register it | 223 | #define R5_PICTURE_OUTSIDE_BOXING_ON 0x02 |
125 | */ | ||
126 | 224 | ||
127 | if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0) | 225 | #define R5_TEXT_INSIDE_BOXING_OFF 0x00 |
128 | { | 226 | #define R5_TEXT_INSIDE_BOXING_ON 0x04 |
129 | kfree(t); | ||
130 | kfree(client); | ||
131 | video_device_release(vd); | ||
132 | return err; | ||
133 | } | ||
134 | t->client = client; | ||
135 | i2c_attach_client(client); | ||
136 | return 0; | ||
137 | } | ||
138 | 227 | ||
139 | /* | 228 | #define R5_TEXT_OUTSIDE_BOXING_OFF 0x00 |
140 | * We do most of the hard work when we become a device on the i2c. | 229 | #define R5_TEXT_OUTSIDE_BOXING_ON 0x08 |
141 | */ | ||
142 | static int saa5246a_probe(struct i2c_adapter *adap) | ||
143 | { | ||
144 | if (adap->class & I2C_CLASS_TV_ANALOG) | ||
145 | return i2c_probe(adap, &addr_data, saa5246a_attach); | ||
146 | return 0; | ||
147 | } | ||
148 | 230 | ||
149 | static int saa5246a_detach(struct i2c_client *client) | 231 | #define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00 |
150 | { | 232 | #define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10 |
151 | struct video_device *vd = i2c_get_clientdata(client); | ||
152 | 233 | ||
153 | i2c_detach_client(client); | 234 | #define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00 |
154 | video_unregister_device(vd); | 235 | #define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20 |
155 | kfree(video_get_drvdata(vd)); | ||
156 | kfree(client); | ||
157 | return 0; | ||
158 | } | ||
159 | 236 | ||
160 | /* | 237 | #define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00 |
161 | * I2C interfaces | 238 | #define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40 |
162 | */ | 239 | |
240 | #define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00 | ||
241 | #define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80 | ||
242 | |||
243 | /* Register R6 (Newsflash display) */ | ||
244 | #define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF 0x00 | ||
245 | #define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON 0x01 | ||
246 | |||
247 | #define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF 0x00 | ||
248 | #define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON 0x02 | ||
249 | |||
250 | #define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF 0x00 | ||
251 | #define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON 0x04 | ||
252 | |||
253 | #define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF 0x00 | ||
254 | #define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON 0x08 | ||
255 | |||
256 | #define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00 | ||
257 | #define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10 | ||
258 | |||
259 | #define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00 | ||
260 | #define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20 | ||
261 | |||
262 | #define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00 | ||
263 | #define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40 | ||
264 | |||
265 | #define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00 | ||
266 | #define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80 | ||
267 | |||
268 | /* Register R7 (Display mode) */ | ||
269 | #define R7_BOX_OFF_ROW_0 0x00 | ||
270 | #define R7_BOX_ON_ROW_0 0x01 | ||
271 | |||
272 | #define R7_BOX_OFF_ROW_1_TO_23 0x00 | ||
273 | #define R7_BOX_ON_ROW_1_TO_23 0x02 | ||
274 | |||
275 | #define R7_BOX_OFF_ROW_24 0x00 | ||
276 | #define R7_BOX_ON_ROW_24 0x04 | ||
277 | |||
278 | #define R7_SINGLE_HEIGHT 0x00 | ||
279 | #define R7_DOUBLE_HEIGHT 0x08 | ||
280 | |||
281 | #define R7_TOP_HALF 0x00 | ||
282 | #define R7_BOTTOM_HALF 0x10 | ||
283 | |||
284 | #define R7_REVEAL_OFF 0x00 | ||
285 | #define R7_REVEAL_ON 0x20 | ||
286 | |||
287 | #define R7_CURSER_OFF 0x00 | ||
288 | #define R7_CURSER_ON 0x40 | ||
289 | |||
290 | #define R7_STATUS_BOTTOM 0x00 | ||
291 | #define R7_STATUS_TOP 0x80 | ||
292 | |||
293 | /* Register R8 (Active chapter) */ | ||
294 | #define R8_ACTIVE_CHAPTER_0 0x00 | ||
295 | #define R8_ACTIVE_CHAPTER_1 0x01 | ||
296 | #define R8_ACTIVE_CHAPTER_2 0x02 | ||
297 | #define R8_ACTIVE_CHAPTER_3 0x03 | ||
298 | #define R8_ACTIVE_CHAPTER_4 0x04 | ||
299 | #define R8_ACTIVE_CHAPTER_5 0x05 | ||
300 | #define R8_ACTIVE_CHAPTER_6 0x06 | ||
301 | #define R8_ACTIVE_CHAPTER_7 0x07 | ||
163 | 302 | ||
164 | static struct i2c_driver i2c_driver_videotext = | 303 | #define R8_CLEAR_MEMORY 0x08 |
304 | #define R8_DO_NOT_CLEAR_MEMORY 0x00 | ||
305 | |||
306 | /* Register R9 (Curser row) */ | ||
307 | #define R9_CURSER_ROW_0 0x00 | ||
308 | #define R9_CURSER_ROW_1 0x01 | ||
309 | #define R9_CURSER_ROW_2 0x02 | ||
310 | #define R9_CURSER_ROW_25 0x19 | ||
311 | |||
312 | /* Register R10 (Curser column) */ | ||
313 | #define R10_CURSER_COLUMN_0 0x00 | ||
314 | #define R10_CURSER_COLUMN_6 0x06 | ||
315 | #define R10_CURSER_COLUMN_8 0x08 | ||
316 | |||
317 | /*****************************************************************************/ | ||
318 | /* Row 25 control data in column 0 to 9 */ | ||
319 | /*****************************************************************************/ | ||
320 | #define ROW25_COLUMN0_PAGE_UNITS 0x0F | ||
321 | |||
322 | #define ROW25_COLUMN1_PAGE_TENS 0x0F | ||
323 | |||
324 | #define ROW25_COLUMN2_MINUTES_UNITS 0x0F | ||
325 | |||
326 | #define ROW25_COLUMN3_MINUTES_TENS 0x07 | ||
327 | #define ROW25_COLUMN3_DELETE_PAGE 0x08 | ||
328 | |||
329 | #define ROW25_COLUMN4_HOUR_UNITS 0x0F | ||
330 | |||
331 | #define ROW25_COLUMN5_HOUR_TENS 0x03 | ||
332 | #define ROW25_COLUMN5_INSERT_HEADLINE 0x04 | ||
333 | #define ROW25_COLUMN5_INSERT_SUBTITLE 0x08 | ||
334 | |||
335 | #define ROW25_COLUMN6_SUPPRESS_HEADER 0x01 | ||
336 | #define ROW25_COLUMN6_UPDATE_PAGE 0x02 | ||
337 | #define ROW25_COLUMN6_INTERRUPTED_SEQUENCE 0x04 | ||
338 | #define ROW25_COLUMN6_SUPPRESS_DISPLAY 0x08 | ||
339 | |||
340 | #define ROW25_COLUMN7_SERIAL_MODE 0x01 | ||
341 | #define ROW25_COLUMN7_CHARACTER_SET 0x0E | ||
342 | |||
343 | #define ROW25_COLUMN8_PAGE_HUNDREDS 0x07 | ||
344 | #define ROW25_COLUMN8_PAGE_NOT_FOUND 0x10 | ||
345 | |||
346 | #define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR 0x20 | ||
347 | |||
348 | #define ROW25_COLUMN0_TO_7_HAMMING_ERROR 0x10 | ||
349 | |||
350 | /*****************************************************************************/ | ||
351 | /* Helper macros for extracting page, hour and minute digits */ | ||
352 | /*****************************************************************************/ | ||
353 | /* BYTE_POS 0 is at row 0, column 0, | ||
354 | BYTE_POS 1 is at row 0, column 1, | ||
355 | BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40) | ||
356 | BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40), | ||
357 | ... */ | ||
358 | #define ROW(BYTE_POS) (BYTE_POS / NUM_ROWS_PER_PAGE) | ||
359 | #define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE) | ||
360 | |||
361 | /*****************************************************************************/ | ||
362 | /* Helper macros for extracting page, hour and minute digits */ | ||
363 | /*****************************************************************************/ | ||
364 | /* Macros for extracting hundreds, tens and units of a page number which | ||
365 | must be in the range 0 ... 0x799. | ||
366 | Note that page is coded in hexadecimal, i.e. 0x123 means page 123. | ||
367 | page 0x.. means page 8.. */ | ||
368 | #define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7) | ||
369 | #define TENS_OF_PAGE(page) (((page) / 0x10) & 0xF) | ||
370 | #define UNITS_OF_PAGE(page) ((page) & 0xF) | ||
371 | |||
372 | /* Macros for extracting tens and units of a hour information which | ||
373 | must be in the range 0 ... 0x24. | ||
374 | Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */ | ||
375 | #define TENS_OF_HOUR(hour) ((hour) / 0x10) | ||
376 | #define UNITS_OF_HOUR(hour) ((hour) & 0xF) | ||
377 | |||
378 | /* Macros for extracting tens and units of a minute information which | ||
379 | must be in the range 0 ... 0x59. | ||
380 | Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */ | ||
381 | #define TENS_OF_MINUTE(minute) ((minute) / 0x10) | ||
382 | #define UNITS_OF_MINUTE(minute) ((minute) & 0xF) | ||
383 | |||
384 | #define HOUR_MAX 0x23 | ||
385 | #define MINUTE_MAX 0x59 | ||
386 | #define PAGE_MAX 0x8FF | ||
387 | |||
388 | |||
389 | struct saa5246a_device | ||
165 | { | 390 | { |
166 | .driver = { | 391 | u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE]; |
167 | .name = IF_NAME, /* name */ | 392 | int is_searching[NUM_DAUS]; |
168 | }, | 393 | struct i2c_client *client; |
169 | .id = I2C_DRIVERID_SAA5249, /* in i2c.h */ | 394 | unsigned long in_use; |
170 | .attach_adapter = saa5246a_probe, | 395 | struct mutex lock; |
171 | .detach_client = saa5246a_detach, | ||
172 | }; | 396 | }; |
173 | 397 | ||
174 | static struct i2c_client client_template = { | 398 | static struct video_device saa_template; /* Declared near bottom */ |
175 | .driver = &i2c_driver_videotext, | 399 | |
176 | .name = "(unset)", | 400 | /* |
177 | }; | 401 | * I2C interfaces |
402 | */ | ||
178 | 403 | ||
179 | static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data) | 404 | static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data) |
180 | { | 405 | { |
@@ -794,22 +1019,6 @@ static int saa5246a_release(struct inode *inode, struct file *file) | |||
794 | return 0; | 1019 | return 0; |
795 | } | 1020 | } |
796 | 1021 | ||
797 | static int __init init_saa_5246a (void) | ||
798 | { | ||
799 | printk(KERN_INFO | ||
800 | "SAA5246A (or compatible) Teletext decoder driver version %d.%d\n", | ||
801 | MAJOR_VERSION, MINOR_VERSION); | ||
802 | return i2c_add_driver(&i2c_driver_videotext); | ||
803 | } | ||
804 | |||
805 | static void __exit cleanup_saa_5246a (void) | ||
806 | { | ||
807 | i2c_del_driver(&i2c_driver_videotext); | ||
808 | } | ||
809 | |||
810 | module_init(init_saa_5246a); | ||
811 | module_exit(cleanup_saa_5246a); | ||
812 | |||
813 | static const struct file_operations saa_fops = { | 1022 | static const struct file_operations saa_fops = { |
814 | .owner = THIS_MODULE, | 1023 | .owner = THIS_MODULE, |
815 | .open = saa5246a_open, | 1024 | .open = saa5246a_open, |
@@ -820,8 +1029,79 @@ static const struct file_operations saa_fops = { | |||
820 | 1029 | ||
821 | static struct video_device saa_template = | 1030 | static struct video_device saa_template = |
822 | { | 1031 | { |
823 | .name = IF_NAME, | 1032 | .name = "saa5246a", |
824 | .fops = &saa_fops, | 1033 | .fops = &saa_fops, |
825 | .release = video_device_release, | 1034 | .release = video_device_release, |
826 | .minor = -1, | 1035 | .minor = -1, |
827 | }; | 1036 | }; |
1037 | |||
1038 | /* Addresses to scan */ | ||
1039 | static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; | ||
1040 | |||
1041 | I2C_CLIENT_INSMOD; | ||
1042 | |||
1043 | static int saa5246a_probe(struct i2c_client *client, | ||
1044 | const struct i2c_device_id *id) | ||
1045 | { | ||
1046 | int pgbuf; | ||
1047 | int err; | ||
1048 | struct video_device *vd; | ||
1049 | struct saa5246a_device *t; | ||
1050 | |||
1051 | v4l_info(client, "chip found @ 0x%x (%s)\n", | ||
1052 | client->addr << 1, client->adapter->name); | ||
1053 | v4l_info(client, "VideoText version %d.%d\n", | ||
1054 | MAJOR_VERSION, MINOR_VERSION); | ||
1055 | t = kzalloc(sizeof(*t), GFP_KERNEL); | ||
1056 | if (t == NULL) | ||
1057 | return -ENOMEM; | ||
1058 | mutex_init(&t->lock); | ||
1059 | |||
1060 | /* Now create a video4linux device */ | ||
1061 | vd = video_device_alloc(); | ||
1062 | if (vd == NULL) { | ||
1063 | kfree(t); | ||
1064 | return -ENOMEM; | ||
1065 | } | ||
1066 | i2c_set_clientdata(client, vd); | ||
1067 | memcpy(vd, &saa_template, sizeof(*vd)); | ||
1068 | |||
1069 | for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { | ||
1070 | memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0])); | ||
1071 | t->is_searching[pgbuf] = false; | ||
1072 | } | ||
1073 | video_set_drvdata(vd, t); | ||
1074 | |||
1075 | /* Register it */ | ||
1076 | err = video_register_device(vd, VFL_TYPE_VTX, -1); | ||
1077 | if (err < 0) { | ||
1078 | kfree(t); | ||
1079 | video_device_release(vd); | ||
1080 | return err; | ||
1081 | } | ||
1082 | t->client = client; | ||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static int saa5246a_remove(struct i2c_client *client) | ||
1087 | { | ||
1088 | struct video_device *vd = i2c_get_clientdata(client); | ||
1089 | |||
1090 | video_unregister_device(vd); | ||
1091 | kfree(video_get_drvdata(vd)); | ||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | static const struct i2c_device_id saa5246a_id[] = { | ||
1096 | { "saa5246a", 0 }, | ||
1097 | { } | ||
1098 | }; | ||
1099 | MODULE_DEVICE_TABLE(i2c, saa5246a_id); | ||
1100 | |||
1101 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { | ||
1102 | .name = "saa5246a", | ||
1103 | .driverid = I2C_DRIVERID_SAA5249, | ||
1104 | .probe = saa5246a_probe, | ||
1105 | .remove = saa5246a_remove, | ||
1106 | .id_table = saa5246a_id, | ||
1107 | }; | ||