diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/video/zr36016.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/media/video/zr36016.c')
-rw-r--r-- | drivers/media/video/zr36016.c | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c new file mode 100644 index 000000000000..d4740a89cea1 --- /dev/null +++ b/drivers/media/video/zr36016.c | |||
@@ -0,0 +1,532 @@ | |||
1 | /* | ||
2 | * Zoran ZR36016 basic configuration functions | ||
3 | * | ||
4 | * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> | ||
5 | * | ||
6 | * $Id: zr36016.c,v 1.1.2.14 2003/08/20 19:46:55 rbultje Exp $ | ||
7 | * | ||
8 | * ------------------------------------------------------------------------ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | * ------------------------------------------------------------------------ | ||
25 | */ | ||
26 | |||
27 | #define ZR016_VERSION "v0.7" | ||
28 | |||
29 | #include <linux/version.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/delay.h> | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/wait.h> | ||
37 | |||
38 | /* includes for structures and defines regarding video | ||
39 | #include<linux/videodev.h> */ | ||
40 | |||
41 | /* I/O commands, error codes */ | ||
42 | #include<asm/io.h> | ||
43 | //#include<errno.h> | ||
44 | |||
45 | /* v4l API */ | ||
46 | #include<linux/videodev.h> | ||
47 | |||
48 | /* headerfile of this module */ | ||
49 | #include"zr36016.h" | ||
50 | |||
51 | /* codec io API */ | ||
52 | #include"videocodec.h" | ||
53 | |||
54 | /* it doesn't make sense to have more than 20 or so, | ||
55 | just to prevent some unwanted loops */ | ||
56 | #define MAX_CODECS 20 | ||
57 | |||
58 | /* amount of chips attached via this driver */ | ||
59 | static int zr36016_codecs = 0; | ||
60 | |||
61 | /* debugging is available via module parameter */ | ||
62 | |||
63 | static int debug = 0; | ||
64 | module_param(debug, int, 0); | ||
65 | MODULE_PARM_DESC(debug, "Debug level (0-4)"); | ||
66 | |||
67 | #define dprintk(num, format, args...) \ | ||
68 | do { \ | ||
69 | if (debug >= num) \ | ||
70 | printk(format, ##args); \ | ||
71 | } while (0) | ||
72 | |||
73 | /* ========================================================================= | ||
74 | Local hardware I/O functions: | ||
75 | |||
76 | read/write via codec layer (registers are located in the master device) | ||
77 | ========================================================================= */ | ||
78 | |||
79 | /* read and write functions */ | ||
80 | static u8 | ||
81 | zr36016_read (struct zr36016 *ptr, | ||
82 | u16 reg) | ||
83 | { | ||
84 | u8 value = 0; | ||
85 | |||
86 | // just in case something is wrong... | ||
87 | if (ptr->codec->master_data->readreg) | ||
88 | value = | ||
89 | (ptr->codec->master_data-> | ||
90 | readreg(ptr->codec, reg)) & 0xFF; | ||
91 | else | ||
92 | dprintk(1, | ||
93 | KERN_ERR "%s: invalid I/O setup, nothing read!\n", | ||
94 | ptr->name); | ||
95 | |||
96 | dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, | ||
97 | value); | ||
98 | |||
99 | return value; | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | zr36016_write (struct zr36016 *ptr, | ||
104 | u16 reg, | ||
105 | u8 value) | ||
106 | { | ||
107 | dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, | ||
108 | reg); | ||
109 | |||
110 | // just in case something is wrong... | ||
111 | if (ptr->codec->master_data->writereg) { | ||
112 | ptr->codec->master_data->writereg(ptr->codec, reg, value); | ||
113 | } else | ||
114 | dprintk(1, | ||
115 | KERN_ERR | ||
116 | "%s: invalid I/O setup, nothing written!\n", | ||
117 | ptr->name); | ||
118 | } | ||
119 | |||
120 | /* indirect read and write functions */ | ||
121 | /* the 016 supports auto-addr-increment, but | ||
122 | * writing it all time cost not much and is safer... */ | ||
123 | static u8 | ||
124 | zr36016_readi (struct zr36016 *ptr, | ||
125 | u16 reg) | ||
126 | { | ||
127 | u8 value = 0; | ||
128 | |||
129 | // just in case something is wrong... | ||
130 | if ((ptr->codec->master_data->writereg) && | ||
131 | (ptr->codec->master_data->readreg)) { | ||
132 | ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR | ||
133 | value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA | ||
134 | } else | ||
135 | dprintk(1, | ||
136 | KERN_ERR | ||
137 | "%s: invalid I/O setup, nothing read (i)!\n", | ||
138 | ptr->name); | ||
139 | |||
140 | dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, | ||
141 | reg, value); | ||
142 | return value; | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | zr36016_writei (struct zr36016 *ptr, | ||
147 | u16 reg, | ||
148 | u8 value) | ||
149 | { | ||
150 | dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, | ||
151 | value, reg); | ||
152 | |||
153 | // just in case something is wrong... | ||
154 | if (ptr->codec->master_data->writereg) { | ||
155 | ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR | ||
156 | ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA | ||
157 | } else | ||
158 | dprintk(1, | ||
159 | KERN_ERR | ||
160 | "%s: invalid I/O setup, nothing written (i)!\n", | ||
161 | ptr->name); | ||
162 | } | ||
163 | |||
164 | /* ========================================================================= | ||
165 | Local helper function: | ||
166 | |||
167 | version read | ||
168 | ========================================================================= */ | ||
169 | |||
170 | /* version kept in datastructure */ | ||
171 | static u8 | ||
172 | zr36016_read_version (struct zr36016 *ptr) | ||
173 | { | ||
174 | ptr->version = zr36016_read(ptr, 0) >> 4; | ||
175 | return ptr->version; | ||
176 | } | ||
177 | |||
178 | /* ========================================================================= | ||
179 | Local helper function: | ||
180 | |||
181 | basic test of "connectivity", writes/reads to/from PAX-Lo register | ||
182 | ========================================================================= */ | ||
183 | |||
184 | static int | ||
185 | zr36016_basic_test (struct zr36016 *ptr) | ||
186 | { | ||
187 | if (debug) { | ||
188 | int i; | ||
189 | zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); | ||
190 | dprintk(1, KERN_INFO "%s: registers: ", ptr->name); | ||
191 | for (i = 0; i <= 0x0b; i++) | ||
192 | dprintk(1, "%02x ", zr36016_readi(ptr, i)); | ||
193 | dprintk(1, "\n"); | ||
194 | } | ||
195 | // for testing just write 0, then the default value to a register and read | ||
196 | // it back in both cases | ||
197 | zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); | ||
198 | if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { | ||
199 | dprintk(1, | ||
200 | KERN_ERR | ||
201 | "%s: attach failed, can't connect to vfe processor!\n", | ||
202 | ptr->name); | ||
203 | return -ENXIO; | ||
204 | } | ||
205 | zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); | ||
206 | if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { | ||
207 | dprintk(1, | ||
208 | KERN_ERR | ||
209 | "%s: attach failed, can't connect to vfe processor!\n", | ||
210 | ptr->name); | ||
211 | return -ENXIO; | ||
212 | } | ||
213 | // we allow version numbers from 0-3, should be enough, though | ||
214 | zr36016_read_version(ptr); | ||
215 | if (ptr->version & 0x0c) { | ||
216 | dprintk(1, | ||
217 | KERN_ERR | ||
218 | "%s: attach failed, suspicious version %d found...\n", | ||
219 | ptr->name, ptr->version); | ||
220 | return -ENXIO; | ||
221 | } | ||
222 | |||
223 | return 0; /* looks good! */ | ||
224 | } | ||
225 | |||
226 | /* ========================================================================= | ||
227 | Local helper function: | ||
228 | |||
229 | simple loop for pushing the init datasets - NO USE -- | ||
230 | ========================================================================= */ | ||
231 | |||
232 | #if 0 | ||
233 | static int zr36016_pushit (struct zr36016 *ptr, | ||
234 | u16 startreg, | ||
235 | u16 len, | ||
236 | const char *data) | ||
237 | { | ||
238 | int i=0; | ||
239 | |||
240 | dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", | ||
241 | ptr->name, startreg,len); | ||
242 | while (i<len) { | ||
243 | zr36016_writei(ptr, startreg++, data[i++]); | ||
244 | } | ||
245 | |||
246 | return i; | ||
247 | } | ||
248 | #endif | ||
249 | |||
250 | /* ========================================================================= | ||
251 | Basic datasets & init: | ||
252 | |||
253 | //TODO// | ||
254 | ========================================================================= */ | ||
255 | |||
256 | // needed offset values PAL NTSC SECAM | ||
257 | static const int zr016_xoff[] = { 20, 20, 20 }; | ||
258 | static const int zr016_yoff[] = { 8, 9, 7 }; | ||
259 | |||
260 | static void | ||
261 | zr36016_init (struct zr36016 *ptr) | ||
262 | { | ||
263 | // stop any processing | ||
264 | zr36016_write(ptr, ZR016_GOSTOP, 0); | ||
265 | |||
266 | // mode setup (yuv422 in and out, compression/expansuon due to mode) | ||
267 | zr36016_write(ptr, ZR016_MODE, | ||
268 | ZR016_YUV422 | ZR016_YUV422_YUV422 | | ||
269 | (ptr->mode == CODEC_DO_COMPRESSION ? | ||
270 | ZR016_COMPRESSION : ZR016_EXPANSION)); | ||
271 | |||
272 | // misc setup | ||
273 | zr36016_writei(ptr, ZR016I_SETUP1, | ||
274 | (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | | ||
275 | (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); | ||
276 | zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); | ||
277 | |||
278 | // Window setup | ||
279 | // (no extra offset for now, norm defines offset, default width height) | ||
280 | zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); | ||
281 | zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); | ||
282 | zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); | ||
283 | zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); | ||
284 | zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); | ||
285 | zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); | ||
286 | zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); | ||
287 | zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); | ||
288 | |||
289 | /* shall we continue now, please? */ | ||
290 | zr36016_write(ptr, ZR016_GOSTOP, 1); | ||
291 | } | ||
292 | |||
293 | /* ========================================================================= | ||
294 | CODEC API FUNCTIONS | ||
295 | |||
296 | this functions are accessed by the master via the API structure | ||
297 | ========================================================================= */ | ||
298 | |||
299 | /* set compression/expansion mode and launches codec - | ||
300 | this should be the last call from the master before starting processing */ | ||
301 | static int | ||
302 | zr36016_set_mode (struct videocodec *codec, | ||
303 | int mode) | ||
304 | { | ||
305 | struct zr36016 *ptr = (struct zr36016 *) codec->data; | ||
306 | |||
307 | dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); | ||
308 | |||
309 | if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) | ||
310 | return -EINVAL; | ||
311 | |||
312 | ptr->mode = mode; | ||
313 | zr36016_init(ptr); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* set picture size */ | ||
319 | static int | ||
320 | zr36016_set_video (struct videocodec *codec, | ||
321 | struct tvnorm *norm, | ||
322 | struct vfe_settings *cap, | ||
323 | struct vfe_polarity *pol) | ||
324 | { | ||
325 | struct zr36016 *ptr = (struct zr36016 *) codec->data; | ||
326 | |||
327 | dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", | ||
328 | ptr->name, norm->HStart, norm->VStart, | ||
329 | cap->x, cap->y, cap->width, cap->height, | ||
330 | cap->decimation); | ||
331 | |||
332 | /* if () return -EINVAL; | ||
333 | * trust the master driver that it knows what it does - so | ||
334 | * we allow invalid startx/y for now ... */ | ||
335 | ptr->width = cap->width; | ||
336 | ptr->height = cap->height; | ||
337 | /* (Ronald) This is ugly. zoran_device.c, line 387 | ||
338 | * already mentions what happens if HStart is even | ||
339 | * (blue faces, etc., cr/cb inversed). There's probably | ||
340 | * some good reason why HStart is 0 instead of 1, so I'm | ||
341 | * leaving it to this for now, but really... This can be | ||
342 | * done a lot simpler */ | ||
343 | ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x; | ||
344 | /* Something to note here (I don't understand it), setting | ||
345 | * VStart too high will cause the codec to 'not work'. I | ||
346 | * really don't get it. values of 16 (VStart) already break | ||
347 | * it here. Just '0' seems to work. More testing needed! */ | ||
348 | ptr->yoff = norm->VStart + cap->y; | ||
349 | /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ | ||
350 | ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; | ||
351 | ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /* additional control functions */ | ||
357 | static int | ||
358 | zr36016_control (struct videocodec *codec, | ||
359 | int type, | ||
360 | int size, | ||
361 | void *data) | ||
362 | { | ||
363 | struct zr36016 *ptr = (struct zr36016 *) codec->data; | ||
364 | int *ival = (int *) data; | ||
365 | |||
366 | dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, | ||
367 | size); | ||
368 | |||
369 | switch (type) { | ||
370 | case CODEC_G_STATUS: /* get last status - we don't know it ... */ | ||
371 | if (size != sizeof(int)) | ||
372 | return -EFAULT; | ||
373 | *ival = 0; | ||
374 | break; | ||
375 | |||
376 | case CODEC_G_CODEC_MODE: | ||
377 | if (size != sizeof(int)) | ||
378 | return -EFAULT; | ||
379 | *ival = 0; | ||
380 | break; | ||
381 | |||
382 | case CODEC_S_CODEC_MODE: | ||
383 | if (size != sizeof(int)) | ||
384 | return -EFAULT; | ||
385 | if (*ival != 0) | ||
386 | return -EINVAL; | ||
387 | /* not needed, do nothing */ | ||
388 | return 0; | ||
389 | |||
390 | case CODEC_G_VFE: | ||
391 | case CODEC_S_VFE: | ||
392 | return 0; | ||
393 | |||
394 | case CODEC_S_MMAP: | ||
395 | /* not available, give an error */ | ||
396 | return -ENXIO; | ||
397 | |||
398 | default: | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | return size; | ||
403 | } | ||
404 | |||
405 | /* ========================================================================= | ||
406 | Exit and unregister function: | ||
407 | |||
408 | Deinitializes Zoran's JPEG processor | ||
409 | ========================================================================= */ | ||
410 | |||
411 | static int | ||
412 | zr36016_unset (struct videocodec *codec) | ||
413 | { | ||
414 | struct zr36016 *ptr = codec->data; | ||
415 | |||
416 | if (ptr) { | ||
417 | /* do wee need some codec deinit here, too ???? */ | ||
418 | |||
419 | dprintk(1, "%s: finished codec #%d\n", ptr->name, | ||
420 | ptr->num); | ||
421 | kfree(ptr); | ||
422 | codec->data = NULL; | ||
423 | |||
424 | zr36016_codecs--; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | return -EFAULT; | ||
429 | } | ||
430 | |||
431 | /* ========================================================================= | ||
432 | Setup and registry function: | ||
433 | |||
434 | Initializes Zoran's JPEG processor | ||
435 | |||
436 | Also sets pixel size, average code size, mode (compr./decompr.) | ||
437 | (the given size is determined by the processor with the video interface) | ||
438 | ========================================================================= */ | ||
439 | |||
440 | static int | ||
441 | zr36016_setup (struct videocodec *codec) | ||
442 | { | ||
443 | struct zr36016 *ptr; | ||
444 | int res; | ||
445 | |||
446 | dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", | ||
447 | zr36016_codecs); | ||
448 | |||
449 | if (zr36016_codecs == MAX_CODECS) { | ||
450 | dprintk(1, | ||
451 | KERN_ERR "zr36016: Can't attach more codecs!\n"); | ||
452 | return -ENOSPC; | ||
453 | } | ||
454 | //mem structure init | ||
455 | codec->data = ptr = kmalloc(sizeof(struct zr36016), GFP_KERNEL); | ||
456 | if (NULL == ptr) { | ||
457 | dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n"); | ||
458 | return -ENOMEM; | ||
459 | } | ||
460 | memset(ptr, 0, sizeof(struct zr36016)); | ||
461 | |||
462 | snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", | ||
463 | zr36016_codecs); | ||
464 | ptr->num = zr36016_codecs++; | ||
465 | ptr->codec = codec; | ||
466 | |||
467 | //testing | ||
468 | res = zr36016_basic_test(ptr); | ||
469 | if (res < 0) { | ||
470 | zr36016_unset(codec); | ||
471 | return res; | ||
472 | } | ||
473 | //final setup | ||
474 | ptr->mode = CODEC_DO_COMPRESSION; | ||
475 | ptr->width = 768; | ||
476 | ptr->height = 288; | ||
477 | ptr->xdec = 1; | ||
478 | ptr->ydec = 0; | ||
479 | zr36016_init(ptr); | ||
480 | |||
481 | dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", | ||
482 | ptr->name, ptr->version); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static const struct videocodec zr36016_codec = { | ||
488 | .owner = THIS_MODULE, | ||
489 | .name = "zr36016", | ||
490 | .magic = 0L, // magic not used | ||
491 | .flags = | ||
492 | CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | | ||
493 | CODEC_FLAG_DECODER, | ||
494 | .type = CODEC_TYPE_ZR36016, | ||
495 | .setup = zr36016_setup, // functionality | ||
496 | .unset = zr36016_unset, | ||
497 | .set_mode = zr36016_set_mode, | ||
498 | .set_video = zr36016_set_video, | ||
499 | .control = zr36016_control, | ||
500 | // others are not used | ||
501 | }; | ||
502 | |||
503 | /* ========================================================================= | ||
504 | HOOK IN DRIVER AS KERNEL MODULE | ||
505 | ========================================================================= */ | ||
506 | |||
507 | static int __init | ||
508 | zr36016_init_module (void) | ||
509 | { | ||
510 | //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION); | ||
511 | zr36016_codecs = 0; | ||
512 | return videocodec_register(&zr36016_codec); | ||
513 | } | ||
514 | |||
515 | static void __exit | ||
516 | zr36016_cleanup_module (void) | ||
517 | { | ||
518 | if (zr36016_codecs) { | ||
519 | dprintk(1, | ||
520 | "zr36016: something's wrong - %d codecs left somehow.\n", | ||
521 | zr36016_codecs); | ||
522 | } | ||
523 | videocodec_unregister(&zr36016_codec); | ||
524 | } | ||
525 | |||
526 | module_init(zr36016_init_module); | ||
527 | module_exit(zr36016_cleanup_module); | ||
528 | |||
529 | MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); | ||
530 | MODULE_DESCRIPTION("Driver module for ZR36016 video frontends " | ||
531 | ZR016_VERSION); | ||
532 | MODULE_LICENSE("GPL"); | ||