]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From 866b8695d67e83f47194731d3a7ba55826a7ec70 Mon Sep 17 00:00:00 2001 |
2 | From: Greg Kroah-Hartman <gregkh@suse.de> | |
3 | Date: Fri, 15 Feb 2008 16:53:09 -0800 | |
4 | Subject: [PATCH 10/23] Staging: add the go7007 video driver | |
5 | Patch-mainline: 2.6.28 | |
6 | ||
7 | Todo: | |
8 | - checkpatch.pl cleanups | |
9 | - sparse cleanups | |
10 | - lots of little modules, should be merged together | |
11 | and added to the build. | |
12 | - testing? | |
13 | - handle churn in v4l layer. | |
14 | ||
15 | Many thanks to Ross Cohen <rcohen@snurgle.org> for cleanup patches on | |
16 | this driver. | |
17 | ||
18 | Cc: Ross Cohen <rcohen@snurgle.org> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
20 | --- | |
21 | drivers/staging/Kconfig | 2 + | |
22 | drivers/staging/Makefile | 1 + | |
23 | drivers/staging/go7007/Kconfig | 25 + | |
24 | drivers/staging/go7007/Makefile | 18 + | |
25 | drivers/staging/go7007/README | 11 + | |
26 | drivers/staging/go7007/go7007-driver.c | 688 +++++++++++++ | |
27 | drivers/staging/go7007/go7007-fw.c | 1639 +++++++++++++++++++++++++++++++ | |
28 | drivers/staging/go7007/go7007-i2c.c | 309 ++++++ | |
29 | drivers/staging/go7007/go7007-priv.h | 279 ++++++ | |
30 | drivers/staging/go7007/go7007-usb.c | 1229 +++++++++++++++++++++++ | |
31 | drivers/staging/go7007/go7007-v4l2.c | 1503 ++++++++++++++++++++++++++++ | |
32 | drivers/staging/go7007/go7007.h | 114 +++ | |
33 | drivers/staging/go7007/saa7134-go7007.c | 484 +++++++++ | |
34 | drivers/staging/go7007/snd-go7007.c | 305 ++++++ | |
35 | drivers/staging/go7007/wis-i2c.h | 55 + | |
36 | drivers/staging/go7007/wis-ov7640.c | 131 +++ | |
37 | drivers/staging/go7007/wis-saa7113.c | 363 +++++++ | |
38 | drivers/staging/go7007/wis-saa7115.c | 492 +++++++++ | |
39 | drivers/staging/go7007/wis-sony-tuner.c | 741 ++++++++++++++ | |
40 | drivers/staging/go7007/wis-tw2804.c | 381 +++++++ | |
41 | drivers/staging/go7007/wis-tw9903.c | 363 +++++++ | |
42 | drivers/staging/go7007/wis-uda1342.c | 136 +++ | |
43 | 22 files changed, 9269 insertions(+), 0 deletions(-) | |
44 | create mode 100644 drivers/staging/go7007/Kconfig | |
45 | create mode 100644 drivers/staging/go7007/Makefile | |
46 | create mode 100644 drivers/staging/go7007/README | |
47 | create mode 100644 drivers/staging/go7007/go7007-driver.c | |
48 | create mode 100644 drivers/staging/go7007/go7007-fw.c | |
49 | create mode 100644 drivers/staging/go7007/go7007-i2c.c | |
50 | create mode 100644 drivers/staging/go7007/go7007-priv.h | |
51 | create mode 100644 drivers/staging/go7007/go7007-usb.c | |
52 | create mode 100644 drivers/staging/go7007/go7007-v4l2.c | |
53 | create mode 100644 drivers/staging/go7007/go7007.h | |
54 | create mode 100644 drivers/staging/go7007/saa7134-go7007.c | |
55 | create mode 100644 drivers/staging/go7007/snd-go7007.c | |
56 | create mode 100644 drivers/staging/go7007/wis-i2c.h | |
57 | create mode 100644 drivers/staging/go7007/wis-ov7640.c | |
58 | create mode 100644 drivers/staging/go7007/wis-saa7113.c | |
59 | create mode 100644 drivers/staging/go7007/wis-saa7115.c | |
60 | create mode 100644 drivers/staging/go7007/wis-sony-tuner.c | |
61 | create mode 100644 drivers/staging/go7007/wis-tw2804.c | |
62 | create mode 100644 drivers/staging/go7007/wis-tw9903.c | |
63 | create mode 100644 drivers/staging/go7007/wis-uda1342.c | |
64 | ||
65 | diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig | |
66 | index 56c73bc..f16bc9c 100644 | |
67 | --- a/drivers/staging/Kconfig | |
68 | +++ b/drivers/staging/Kconfig | |
69 | @@ -31,4 +31,6 @@ source "drivers/staging/sxg/Kconfig" | |
70 | ||
71 | source "drivers/staging/me4000/Kconfig" | |
72 | ||
73 | +source "drivers/staging/go7007/Kconfig" | |
74 | + | |
75 | endif # STAGING | |
76 | diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile | |
77 | index 97df19b..aa61662 100644 | |
78 | --- a/drivers/staging/Makefile | |
79 | +++ b/drivers/staging/Makefile | |
80 | @@ -4,3 +4,4 @@ obj-$(CONFIG_ET131X) += et131x/ | |
81 | obj-$(CONFIG_SLICOSS) += slicoss/ | |
82 | obj-$(CONFIG_SXG) += sxg/ | |
83 | obj-$(CONFIG_ME4000) += me4000/ | |
84 | +obj-$(CONFIG_VIDEO_GO7007) += go7007/ | |
85 | diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig | |
86 | new file mode 100644 | |
87 | index 0000000..57a121c | |
88 | --- /dev/null | |
89 | +++ b/drivers/staging/go7007/Kconfig | |
90 | @@ -0,0 +1,25 @@ | |
91 | +config VIDEO_GO7007 | |
92 | + tristate "Go 7007 support" | |
93 | + depends on VIDEO_DEV && PCI && I2C && INPUT | |
94 | + select VIDEOBUF_DMA_SG | |
95 | + select VIDEO_IR | |
96 | + select VIDEO_TUNER | |
97 | + select VIDEO_TVEEPROM | |
98 | + select CRC32 | |
99 | + default N | |
100 | + ---help--- | |
101 | + This is a video4linux driver for some wierd device... | |
102 | + | |
103 | + To compile this driver as a module, choose M here: the | |
104 | + module will be called go7007 | |
105 | + | |
106 | +config VIDEO_GO7007_USB | |
107 | + tristate "Go 7007 USB support" | |
108 | + depends on VIDEO_GO7007 && USB | |
109 | + default N | |
110 | + ---help--- | |
111 | + This is a video4linux driver for some wierd device... | |
112 | + | |
113 | + To compile this driver as a module, choose M here: the | |
114 | + module will be called go7007-usb | |
115 | + | |
116 | diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/go7007/Makefile | |
117 | new file mode 100644 | |
118 | index 0000000..9b9310c | |
119 | --- /dev/null | |
120 | +++ b/drivers/staging/go7007/Makefile | |
121 | @@ -0,0 +1,18 @@ | |
122 | +#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \ | |
123 | + wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \ | |
124 | + wis-tw2804.o | |
125 | + | |
126 | + | |
127 | +obj-$(CONFIG_VIDEO_GO7007) += go7007.o | |
128 | +obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o | |
129 | + | |
130 | +go7007-objs += go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o snd-go7007.o | |
131 | + | |
132 | + | |
133 | +#ifneq ($(SAA7134_BUILD),) | |
134 | +#obj-m += saa7134-go7007.o | |
135 | +#endif | |
136 | + | |
137 | +EXTRA_CFLAGS += -Idrivers/staging/saa7134 | |
138 | +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | |
139 | +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | |
140 | diff --git a/drivers/staging/go7007/README b/drivers/staging/go7007/README | |
141 | new file mode 100644 | |
142 | index 0000000..48f4476 | |
143 | --- /dev/null | |
144 | +++ b/drivers/staging/go7007/README | |
145 | @@ -0,0 +1,11 @@ | |
146 | +Todo: | |
147 | + - checkpatch.pl cleanups | |
148 | + - sparse cleanups | |
149 | + - lots of little modules, should be merged together | |
150 | + and added to the build. | |
151 | + - testing? | |
152 | + - handle churn in v4l layer. | |
153 | + | |
154 | +Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross | |
155 | +Cohen <rcohen@snurgle.org> as well. | |
156 | + | |
157 | diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c | |
158 | new file mode 100644 | |
159 | index 0000000..5a336ff | |
160 | --- /dev/null | |
161 | +++ b/drivers/staging/go7007/go7007-driver.c | |
162 | @@ -0,0 +1,688 @@ | |
163 | +/* | |
164 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
165 | + * | |
166 | + * This program is free software; you can redistribute it and/or modify | |
167 | + * it under the terms of the GNU General Public License (Version 2) as | |
168 | + * published by the Free Software Foundation. | |
169 | + * | |
170 | + * This program is distributed in the hope that it will be useful, | |
171 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
172 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
173 | + * GNU General Public License for more details. | |
174 | + * | |
175 | + * You should have received a copy of the GNU General Public License | |
176 | + * along with this program; if not, write to the Free Software Foundation, | |
177 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
178 | + */ | |
179 | + | |
180 | +#include <linux/module.h> | |
181 | +#include <linux/version.h> | |
182 | +#include <linux/init.h> | |
183 | +#include <linux/delay.h> | |
184 | +#include <linux/sched.h> | |
185 | +#include <linux/spinlock.h> | |
186 | +#include <linux/unistd.h> | |
187 | +#include <linux/time.h> | |
188 | +#include <linux/mm.h> | |
189 | +#include <linux/vmalloc.h> | |
190 | +#include <linux/device.h> | |
191 | +#include <linux/i2c.h> | |
192 | +#include <linux/firmware.h> | |
193 | +#include <linux/semaphore.h> | |
194 | +#include <linux/uaccess.h> | |
195 | +#include <asm/system.h> | |
196 | +#include <linux/videodev.h> | |
197 | +#include <media/tuner.h> | |
198 | +#include <media/v4l2-common.h> | |
199 | + | |
200 | +#include "go7007-priv.h" | |
201 | +#include "wis-i2c.h" | |
202 | + | |
203 | +/* | |
204 | + * Wait for an interrupt to be delivered from the GO7007SB and return | |
205 | + * the associated value and data. | |
206 | + * | |
207 | + * Must be called with the hw_lock held. | |
208 | + */ | |
209 | +int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data) | |
210 | +{ | |
211 | + go->interrupt_available = 0; | |
212 | + go->hpi_ops->read_interrupt(go); | |
213 | + if (wait_event_timeout(go->interrupt_waitq, | |
214 | + go->interrupt_available, 5*HZ) < 0) { | |
215 | + printk(KERN_ERR "go7007: timeout waiting for read interrupt\n"); | |
216 | + return -1; | |
217 | + } | |
218 | + if (!go->interrupt_available) | |
219 | + return -1; | |
220 | + go->interrupt_available = 0; | |
221 | + *value = go->interrupt_value & 0xfffe; | |
222 | + *data = go->interrupt_data; | |
223 | + return 0; | |
224 | +} | |
225 | +EXPORT_SYMBOL(go7007_read_interrupt); | |
226 | + | |
227 | +/* | |
228 | + * Read a register/address on the GO7007SB. | |
229 | + * | |
230 | + * Must be called with the hw_lock held. | |
231 | + */ | |
232 | +int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data) | |
233 | +{ | |
234 | + int count = 100; | |
235 | + u16 value; | |
236 | + | |
237 | + if (go7007_write_interrupt(go, 0x0010, addr) < 0) | |
238 | + return -EIO; | |
239 | + while (count-- > 0) { | |
240 | + if (go7007_read_interrupt(go, &value, data) == 0 && | |
241 | + value == 0xa000) | |
242 | + return 0; | |
243 | + } | |
244 | + return -EIO; | |
245 | +} | |
246 | +EXPORT_SYMBOL(go7007_read_addr); | |
247 | + | |
248 | +/* | |
249 | + * Send the boot firmware to the encoder, which just wakes it up and lets | |
250 | + * us talk to the GPIO pins and on-board I2C adapter. | |
251 | + * | |
252 | + * Must be called with the hw_lock held. | |
253 | + */ | |
254 | +static int go7007_load_encoder(struct go7007 *go) | |
255 | +{ | |
256 | + const struct firmware *fw_entry; | |
257 | + char fw_name[] = "go7007fw.bin"; | |
258 | + void *bounce; | |
259 | + int fw_len, rv = 0; | |
260 | + u16 intr_val, intr_data; | |
261 | + | |
262 | + if (request_firmware(&fw_entry, fw_name, go->dev)) { | |
263 | + printk(KERN_ERR | |
264 | + "go7007: unable to load firmware from file \"%s\"\n", | |
265 | + fw_name); | |
266 | + return -1; | |
267 | + } | |
268 | + if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) { | |
269 | + printk(KERN_ERR "go7007: file \"%s\" does not appear to be " | |
270 | + "go7007 firmware\n", fw_name); | |
271 | + release_firmware(fw_entry); | |
272 | + return -1; | |
273 | + } | |
274 | + fw_len = fw_entry->size - 16; | |
275 | + bounce = kmalloc(fw_len, GFP_KERNEL); | |
276 | + if (bounce == NULL) { | |
277 | + printk(KERN_ERR "go7007: unable to allocate %d bytes for " | |
278 | + "firmware transfer\n", fw_len); | |
279 | + release_firmware(fw_entry); | |
280 | + return -1; | |
281 | + } | |
282 | + memcpy(bounce, fw_entry->data + 16, fw_len); | |
283 | + release_firmware(fw_entry); | |
284 | + if (go7007_interface_reset(go) < 0 || | |
285 | + go7007_send_firmware(go, bounce, fw_len) < 0 || | |
286 | + go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || | |
287 | + (intr_val & ~0x1) != 0x5a5a) { | |
288 | + printk(KERN_ERR "go7007: error transferring firmware\n"); | |
289 | + rv = -1; | |
290 | + } | |
291 | + kfree(bounce); | |
292 | + return rv; | |
293 | +} | |
294 | + | |
295 | +/* | |
296 | + * Boot the encoder and register the I2C adapter if requested. Do the | |
297 | + * minimum initialization necessary, since the board-specific code may | |
298 | + * still need to probe the board ID. | |
299 | + * | |
300 | + * Must NOT be called with the hw_lock held. | |
301 | + */ | |
302 | +int go7007_boot_encoder(struct go7007 *go, int init_i2c) | |
303 | +{ | |
304 | + int ret; | |
305 | + | |
306 | + down(&go->hw_lock); | |
307 | + ret = go7007_load_encoder(go); | |
308 | + up(&go->hw_lock); | |
309 | + if (ret < 0) | |
310 | + return -1; | |
311 | + if (!init_i2c) | |
312 | + return 0; | |
313 | + if (go7007_i2c_init(go) < 0) | |
314 | + return -1; | |
315 | + go->i2c_adapter_online = 1; | |
316 | + return 0; | |
317 | +} | |
318 | +EXPORT_SYMBOL(go7007_boot_encoder); | |
319 | + | |
320 | +/* | |
321 | + * Configure any hardware-related registers in the GO7007, such as GPIO | |
322 | + * pins and bus parameters, which are board-specific. This assumes | |
323 | + * the boot firmware has already been downloaded. | |
324 | + * | |
325 | + * Must be called with the hw_lock held. | |
326 | + */ | |
327 | +static int go7007_init_encoder(struct go7007 *go) | |
328 | +{ | |
329 | + if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) { | |
330 | + go7007_write_addr(go, 0x1000, 0x0811); | |
331 | + go7007_write_addr(go, 0x1000, 0x0c11); | |
332 | + } | |
333 | + if (go->board_id == GO7007_BOARDID_MATRIX_REV) { | |
334 | + /* Set GPIO pin 0 to be an output (audio clock control) */ | |
335 | + go7007_write_addr(go, 0x3c82, 0x0001); | |
336 | + go7007_write_addr(go, 0x3c80, 0x00fe); | |
337 | + } | |
338 | + return 0; | |
339 | +} | |
340 | + | |
341 | +/* | |
342 | + * Send the boot firmware to the GO7007 and configure the registers. This | |
343 | + * is the only way to stop the encoder once it has started streaming video. | |
344 | + * | |
345 | + * Must be called with the hw_lock held. | |
346 | + */ | |
347 | +int go7007_reset_encoder(struct go7007 *go) | |
348 | +{ | |
349 | + if (go7007_load_encoder(go) < 0) | |
350 | + return -1; | |
351 | + return go7007_init_encoder(go); | |
352 | +} | |
353 | + | |
354 | +/* | |
355 | + * Attempt to instantiate an I2C client by ID, probably loading a module. | |
356 | + */ | |
357 | +static int init_i2c_module(struct i2c_adapter *adapter, int id, int addr) | |
358 | +{ | |
359 | + char *modname; | |
360 | + | |
361 | + switch (id) { | |
362 | + case I2C_DRIVERID_WIS_SAA7115: | |
363 | + modname = "wis-saa7115"; | |
364 | + break; | |
365 | + case I2C_DRIVERID_WIS_SAA7113: | |
366 | + modname = "wis-saa7113"; | |
367 | + break; | |
368 | + case I2C_DRIVERID_WIS_UDA1342: | |
369 | + modname = "wis-uda1342"; | |
370 | + break; | |
371 | + case I2C_DRIVERID_WIS_SONY_TUNER: | |
372 | + modname = "wis-sony-tuner"; | |
373 | + break; | |
374 | + case I2C_DRIVERID_WIS_TW9903: | |
375 | + modname = "wis-tw9903"; | |
376 | + break; | |
377 | + case I2C_DRIVERID_WIS_TW2804: | |
378 | + modname = "wis-tw2804"; | |
379 | + break; | |
380 | + case I2C_DRIVERID_WIS_OV7640: | |
381 | + modname = "wis-ov7640"; | |
382 | + break; | |
383 | + default: | |
384 | + modname = NULL; | |
385 | + break; | |
386 | + } | |
387 | + if (modname != NULL) | |
388 | + request_module(modname); | |
389 | + if (wis_i2c_probe_device(adapter, id, addr) == 1) | |
390 | + return 0; | |
391 | + if (modname != NULL) | |
392 | + printk(KERN_INFO | |
393 | + "go7007: probing for module %s failed", modname); | |
394 | + else | |
395 | + printk(KERN_INFO | |
396 | + "go7007: sensor %u seems to be unsupported!\n", id); | |
397 | + return -1; | |
398 | +} | |
399 | + | |
400 | +/* | |
401 | + * Finalize the GO7007 hardware setup, register the on-board I2C adapter | |
402 | + * (if used on this board), load the I2C client driver for the sensor | |
403 | + * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2 | |
404 | + * interfaces. | |
405 | + * | |
406 | + * Must NOT be called with the hw_lock held. | |
407 | + */ | |
408 | +int go7007_register_encoder(struct go7007 *go) | |
409 | +{ | |
410 | + int i, ret; | |
411 | + | |
412 | + printk(KERN_INFO "go7007: registering new %s\n", go->name); | |
413 | + | |
414 | + down(&go->hw_lock); | |
415 | + ret = go7007_init_encoder(go); | |
416 | + up(&go->hw_lock); | |
417 | + if (ret < 0) | |
418 | + return -1; | |
419 | + | |
420 | + if (!go->i2c_adapter_online && | |
421 | + go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { | |
422 | + if (go7007_i2c_init(go) < 0) | |
423 | + return -1; | |
424 | + go->i2c_adapter_online = 1; | |
425 | + } | |
426 | + if (go->i2c_adapter_online) { | |
427 | + for (i = 0; i < go->board_info->num_i2c_devs; ++i) | |
428 | + init_i2c_module(&go->i2c_adapter, | |
429 | + go->board_info->i2c_devs[i].id, | |
430 | + go->board_info->i2c_devs[i].addr); | |
431 | +#ifdef TUNER_SET_TYPE_ADDR | |
432 | + if (go->tuner_type >= 0) { | |
433 | + struct tuner_setup tun_setup = { | |
434 | + .mode_mask = T_ANALOG_TV, | |
435 | + .addr = ADDR_UNSET, | |
436 | + .type = go->tuner_type | |
437 | + }; | |
438 | + i2c_clients_command(&go->i2c_adapter, | |
439 | + TUNER_SET_TYPE_ADDR, &tun_setup); | |
440 | + } | |
441 | +#else | |
442 | + if (go->tuner_type >= 0) | |
443 | + i2c_clients_command(&go->i2c_adapter, | |
444 | + TUNER_SET_TYPE, &go->tuner_type); | |
445 | +#endif | |
446 | + if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) | |
447 | + i2c_clients_command(&go->i2c_adapter, | |
448 | + DECODER_SET_CHANNEL, &go->channel_number); | |
449 | + } | |
450 | + if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { | |
451 | + go->audio_enabled = 1; | |
452 | + go7007_snd_init(go); | |
453 | + } | |
454 | + return go7007_v4l2_init(go); | |
455 | +} | |
456 | +EXPORT_SYMBOL(go7007_register_encoder); | |
457 | + | |
458 | +/* | |
459 | + * Send the encode firmware to the encoder, which will cause it | |
460 | + * to immediately start delivering the video and audio streams. | |
461 | + * | |
462 | + * Must be called with the hw_lock held. | |
463 | + */ | |
464 | +int go7007_start_encoder(struct go7007 *go) | |
465 | +{ | |
466 | + u8 *fw; | |
467 | + int fw_len, rv = 0, i; | |
468 | + u16 intr_val, intr_data; | |
469 | + | |
470 | + go->modet_enable = 0; | |
471 | + if (!go->dvd_mode) | |
472 | + for (i = 0; i < 4; ++i) { | |
473 | + if (go->modet[i].enable) { | |
474 | + go->modet_enable = 1; | |
475 | + continue; | |
476 | + } | |
477 | + go->modet[i].pixel_threshold = 32767; | |
478 | + go->modet[i].motion_threshold = 32767; | |
479 | + go->modet[i].mb_threshold = 32767; | |
480 | + } | |
481 | + | |
482 | + if (go7007_construct_fw_image(go, &fw, &fw_len) < 0) | |
483 | + return -1; | |
484 | + | |
485 | + if (go7007_send_firmware(go, fw, fw_len) < 0 || | |
486 | + go7007_read_interrupt(go, &intr_val, &intr_data) < 0) { | |
487 | + printk(KERN_ERR "go7007: error transferring firmware\n"); | |
488 | + rv = -1; | |
489 | + goto start_error; | |
490 | + } | |
491 | + | |
492 | + go->state = STATE_DATA; | |
493 | + go->parse_length = 0; | |
494 | + go->seen_frame = 0; | |
495 | + if (go7007_stream_start(go) < 0) { | |
496 | + printk(KERN_ERR "go7007: error starting stream transfer\n"); | |
497 | + rv = -1; | |
498 | + goto start_error; | |
499 | + } | |
500 | + | |
501 | +start_error: | |
502 | + kfree(fw); | |
503 | + return rv; | |
504 | +} | |
505 | + | |
506 | +/* | |
507 | + * Store a byte in the current video buffer, if there is one. | |
508 | + */ | |
509 | +static inline void store_byte(struct go7007_buffer *gobuf, u8 byte) | |
510 | +{ | |
511 | + if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) { | |
512 | + unsigned int pgidx = gobuf->offset >> PAGE_SHIFT; | |
513 | + unsigned int pgoff = gobuf->offset & ~PAGE_MASK; | |
514 | + | |
515 | + *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte; | |
516 | + ++gobuf->offset; | |
517 | + ++gobuf->bytesused; | |
518 | + } | |
519 | +} | |
520 | + | |
521 | +/* | |
522 | + * Deliver the last video buffer and get a new one to start writing to. | |
523 | + */ | |
524 | +static void frame_boundary(struct go7007 *go) | |
525 | +{ | |
526 | + struct go7007_buffer *gobuf; | |
527 | + int i; | |
528 | + | |
529 | + if (go->active_buf) { | |
530 | + if (go->active_buf->modet_active) { | |
531 | + if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) { | |
532 | + for (i = 0; i < 216; ++i) | |
533 | + store_byte(go->active_buf, | |
534 | + go->active_map[i]); | |
535 | + go->active_buf->bytesused -= 216; | |
536 | + } else | |
537 | + go->active_buf->modet_active = 0; | |
538 | + } | |
539 | + go->active_buf->state = BUF_STATE_DONE; | |
540 | + wake_up_interruptible(&go->frame_waitq); | |
541 | + go->active_buf = NULL; | |
542 | + } | |
543 | + list_for_each_entry(gobuf, &go->stream, stream) | |
544 | + if (gobuf->state == BUF_STATE_QUEUED) { | |
545 | + gobuf->seq = go->next_seq; | |
546 | + do_gettimeofday(&gobuf->timestamp); | |
547 | + go->active_buf = gobuf; | |
548 | + break; | |
549 | + } | |
550 | + ++go->next_seq; | |
551 | +} | |
552 | + | |
553 | +static void write_bitmap_word(struct go7007 *go) | |
554 | +{ | |
555 | + int x, y, i, stride = ((go->width >> 4) + 7) >> 3; | |
556 | + | |
557 | + for (i = 0; i < 16; ++i) { | |
558 | + y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4); | |
559 | + x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4); | |
560 | + go->active_map[stride * y + (x >> 3)] |= | |
561 | + (go->modet_word & 1) << (x & 0x7); | |
562 | + go->modet_word >>= 1; | |
563 | + } | |
564 | +} | |
565 | + | |
566 | +/* | |
567 | + * Parse a chunk of the video stream into frames. The frames are not | |
568 | + * delimited by the hardware, so we have to parse the frame boundaries | |
569 | + * based on the type of video stream we're receiving. | |
570 | + */ | |
571 | +void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) | |
572 | +{ | |
573 | + int i, seq_start_code = -1, frame_start_code = -1; | |
574 | + | |
575 | + spin_lock(&go->spinlock); | |
576 | + | |
577 | + switch (go->format) { | |
578 | + case GO7007_FORMAT_MPEG4: | |
579 | + seq_start_code = 0xB0; | |
580 | + frame_start_code = 0xB6; | |
581 | + break; | |
582 | + case GO7007_FORMAT_MPEG1: | |
583 | + case GO7007_FORMAT_MPEG2: | |
584 | + seq_start_code = 0xB3; | |
585 | + frame_start_code = 0x00; | |
586 | + break; | |
587 | + } | |
588 | + | |
589 | + for (i = 0; i < length; ++i) { | |
590 | + if (go->active_buf != NULL && | |
591 | + go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) { | |
592 | + printk(KERN_DEBUG "go7007: dropping oversized frame\n"); | |
593 | + go->active_buf->offset -= go->active_buf->bytesused; | |
594 | + go->active_buf->bytesused = 0; | |
595 | + go->active_buf->modet_active = 0; | |
596 | + go->active_buf = NULL; | |
597 | + } | |
598 | + | |
599 | + switch (go->state) { | |
600 | + case STATE_DATA: | |
601 | + switch (buf[i]) { | |
602 | + case 0x00: | |
603 | + go->state = STATE_00; | |
604 | + break; | |
605 | + case 0xFF: | |
606 | + go->state = STATE_FF; | |
607 | + break; | |
608 | + default: | |
609 | + store_byte(go->active_buf, buf[i]); | |
610 | + break; | |
611 | + } | |
612 | + break; | |
613 | + case STATE_00: | |
614 | + switch (buf[i]) { | |
615 | + case 0x00: | |
616 | + go->state = STATE_00_00; | |
617 | + break; | |
618 | + case 0xFF: | |
619 | + store_byte(go->active_buf, 0x00); | |
620 | + go->state = STATE_FF; | |
621 | + break; | |
622 | + default: | |
623 | + store_byte(go->active_buf, 0x00); | |
624 | + store_byte(go->active_buf, buf[i]); | |
625 | + go->state = STATE_DATA; | |
626 | + break; | |
627 | + } | |
628 | + break; | |
629 | + case STATE_00_00: | |
630 | + switch (buf[i]) { | |
631 | + case 0x00: | |
632 | + store_byte(go->active_buf, 0x00); | |
633 | + /* go->state remains STATE_00_00 */ | |
634 | + break; | |
635 | + case 0x01: | |
636 | + go->state = STATE_00_00_01; | |
637 | + break; | |
638 | + case 0xFF: | |
639 | + store_byte(go->active_buf, 0x00); | |
640 | + store_byte(go->active_buf, 0x00); | |
641 | + go->state = STATE_FF; | |
642 | + break; | |
643 | + default: | |
644 | + store_byte(go->active_buf, 0x00); | |
645 | + store_byte(go->active_buf, 0x00); | |
646 | + store_byte(go->active_buf, buf[i]); | |
647 | + go->state = STATE_DATA; | |
648 | + break; | |
649 | + } | |
650 | + break; | |
651 | + case STATE_00_00_01: | |
652 | + /* If this is the start of a new MPEG frame, | |
653 | + * get a new buffer */ | |
654 | + if ((go->format == GO7007_FORMAT_MPEG1 || | |
655 | + go->format == GO7007_FORMAT_MPEG2 || | |
656 | + go->format == GO7007_FORMAT_MPEG4) && | |
657 | + (buf[i] == seq_start_code || | |
658 | + buf[i] == 0xB8 || /* GOP code */ | |
659 | + buf[i] == frame_start_code)) { | |
660 | + if (go->active_buf == NULL || go->seen_frame) | |
661 | + frame_boundary(go); | |
662 | + if (buf[i] == frame_start_code) { | |
663 | + if (go->active_buf != NULL) | |
664 | + go->active_buf->frame_offset = | |
665 | + go->active_buf->offset; | |
666 | + go->seen_frame = 1; | |
667 | + } else { | |
668 | + go->seen_frame = 0; | |
669 | + } | |
670 | + } | |
671 | + /* Handle any special chunk types, or just write the | |
672 | + * start code to the (potentially new) buffer */ | |
673 | + switch (buf[i]) { | |
674 | + case 0xF5: /* timestamp */ | |
675 | + go->parse_length = 12; | |
676 | + go->state = STATE_UNPARSED; | |
677 | + break; | |
678 | + case 0xF6: /* vbi */ | |
679 | + go->state = STATE_VBI_LEN_A; | |
680 | + break; | |
681 | + case 0xF8: /* MD map */ | |
682 | + go->parse_length = 0; | |
683 | + memset(go->active_map, 0, | |
684 | + sizeof(go->active_map)); | |
685 | + go->state = STATE_MODET_MAP; | |
686 | + break; | |
687 | + case 0xFF: /* Potential JPEG start code */ | |
688 | + store_byte(go->active_buf, 0x00); | |
689 | + store_byte(go->active_buf, 0x00); | |
690 | + store_byte(go->active_buf, 0x01); | |
691 | + go->state = STATE_FF; | |
692 | + break; | |
693 | + default: | |
694 | + store_byte(go->active_buf, 0x00); | |
695 | + store_byte(go->active_buf, 0x00); | |
696 | + store_byte(go->active_buf, 0x01); | |
697 | + store_byte(go->active_buf, buf[i]); | |
698 | + go->state = STATE_DATA; | |
699 | + break; | |
700 | + } | |
701 | + break; | |
702 | + case STATE_FF: | |
703 | + switch (buf[i]) { | |
704 | + case 0x00: | |
705 | + store_byte(go->active_buf, 0xFF); | |
706 | + go->state = STATE_00; | |
707 | + break; | |
708 | + case 0xFF: | |
709 | + store_byte(go->active_buf, 0xFF); | |
710 | + /* go->state remains STATE_FF */ | |
711 | + break; | |
712 | + case 0xD8: | |
713 | + if (go->format == GO7007_FORMAT_MJPEG) | |
714 | + frame_boundary(go); | |
715 | + /* fall through */ | |
716 | + default: | |
717 | + store_byte(go->active_buf, 0xFF); | |
718 | + store_byte(go->active_buf, buf[i]); | |
719 | + go->state = STATE_DATA; | |
720 | + break; | |
721 | + } | |
722 | + break; | |
723 | + case STATE_VBI_LEN_A: | |
724 | + go->parse_length = buf[i] << 8; | |
725 | + go->state = STATE_VBI_LEN_B; | |
726 | + break; | |
727 | + case STATE_VBI_LEN_B: | |
728 | + go->parse_length |= buf[i]; | |
729 | + if (go->parse_length > 0) | |
730 | + go->state = STATE_UNPARSED; | |
731 | + else | |
732 | + go->state = STATE_DATA; | |
733 | + break; | |
734 | + case STATE_MODET_MAP: | |
735 | + if (go->parse_length < 204) { | |
736 | + if (go->parse_length & 1) { | |
737 | + go->modet_word |= buf[i]; | |
738 | + write_bitmap_word(go); | |
739 | + } else | |
740 | + go->modet_word = buf[i] << 8; | |
741 | + } else if (go->parse_length == 207 && go->active_buf) { | |
742 | + go->active_buf->modet_active = buf[i]; | |
743 | + } | |
744 | + if (++go->parse_length == 208) | |
745 | + go->state = STATE_DATA; | |
746 | + break; | |
747 | + case STATE_UNPARSED: | |
748 | + if (--go->parse_length == 0) | |
749 | + go->state = STATE_DATA; | |
750 | + break; | |
751 | + } | |
752 | + } | |
753 | + | |
754 | + spin_unlock(&go->spinlock); | |
755 | +} | |
756 | +EXPORT_SYMBOL(go7007_parse_video_stream); | |
757 | + | |
758 | +/* | |
759 | + * Allocate a new go7007 struct. Used by the hardware-specific probe. | |
760 | + */ | |
761 | +struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) | |
762 | +{ | |
763 | + struct go7007 *go; | |
764 | + int i; | |
765 | + | |
766 | + go = kmalloc(sizeof(struct go7007), GFP_KERNEL); | |
767 | + if (go == NULL) | |
768 | + return NULL; | |
769 | + go->dev = dev; | |
770 | + go->board_info = board; | |
771 | + go->board_id = 0; | |
772 | + go->tuner_type = -1; | |
773 | + go->channel_number = 0; | |
774 | + go->name[0] = 0; | |
775 | + init_MUTEX(&go->hw_lock); | |
776 | + init_waitqueue_head(&go->frame_waitq); | |
777 | + spin_lock_init(&go->spinlock); | |
778 | + go->video_dev = NULL; | |
779 | + go->ref_count = 0; | |
780 | + go->status = STATUS_INIT; | |
781 | + memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); | |
782 | + go->i2c_adapter_online = 0; | |
783 | + go->interrupt_available = 0; | |
784 | + init_waitqueue_head(&go->interrupt_waitq); | |
785 | + go->in_use = 0; | |
786 | + go->input = 0; | |
787 | + if (board->sensor_flags & GO7007_SENSOR_TV) { | |
788 | + go->standard = GO7007_STD_NTSC; | |
789 | + go->width = 720; | |
790 | + go->height = 480; | |
791 | + go->sensor_framerate = 30000; | |
792 | + } else { | |
793 | + go->standard = GO7007_STD_OTHER; | |
794 | + go->width = board->sensor_width; | |
795 | + go->height = board->sensor_height; | |
796 | + go->sensor_framerate = board->sensor_framerate; | |
797 | + } | |
798 | + go->encoder_v_offset = board->sensor_v_offset; | |
799 | + go->encoder_h_offset = board->sensor_h_offset; | |
800 | + go->encoder_h_halve = 0; | |
801 | + go->encoder_v_halve = 0; | |
802 | + go->encoder_subsample = 0; | |
803 | + go->streaming = 0; | |
804 | + go->format = GO7007_FORMAT_MJPEG; | |
805 | + go->bitrate = 1500000; | |
806 | + go->fps_scale = 1; | |
807 | + go->pali = 0; | |
808 | + go->aspect_ratio = GO7007_RATIO_1_1; | |
809 | + go->gop_size = 0; | |
810 | + go->ipb = 0; | |
811 | + go->closed_gop = 0; | |
812 | + go->repeat_seqhead = 0; | |
813 | + go->seq_header_enable = 0; | |
814 | + go->gop_header_enable = 0; | |
815 | + go->dvd_mode = 0; | |
816 | + go->interlace_coding = 0; | |
817 | + for (i = 0; i < 4; ++i) | |
818 | + go->modet[i].enable = 0;; | |
819 | + for (i = 0; i < 1624; ++i) | |
820 | + go->modet_map[i] = 0; | |
821 | + go->audio_deliver = NULL; | |
822 | + go->audio_enabled = 0; | |
823 | + INIT_LIST_HEAD(&go->stream); | |
824 | + | |
825 | + return go; | |
826 | +} | |
827 | +EXPORT_SYMBOL(go7007_alloc); | |
828 | + | |
829 | +/* | |
830 | + * Detach and unregister the encoder. The go7007 struct won't be freed | |
831 | + * until v4l2 finishes releasing its resources and all associated fds are | |
832 | + * closed by applications. | |
833 | + */ | |
834 | +void go7007_remove(struct go7007 *go) | |
835 | +{ | |
836 | + if (go->i2c_adapter_online) { | |
837 | + if (i2c_del_adapter(&go->i2c_adapter) == 0) | |
838 | + go->i2c_adapter_online = 0; | |
839 | + else | |
840 | + printk(KERN_ERR | |
841 | + "go7007: error removing I2C adapter!\n"); | |
842 | + } | |
843 | + | |
844 | + if (go->audio_enabled) | |
845 | + go7007_snd_remove(go); | |
846 | + go7007_v4l2_remove(go); | |
847 | +} | |
848 | +EXPORT_SYMBOL(go7007_remove); | |
849 | + | |
850 | +MODULE_LICENSE("GPL v2"); | |
851 | diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c | |
852 | new file mode 100644 | |
853 | index 0000000..c2aea10 | |
854 | --- /dev/null | |
855 | +++ b/drivers/staging/go7007/go7007-fw.c | |
856 | @@ -0,0 +1,1639 @@ | |
857 | +/* | |
858 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
859 | + * | |
860 | + * This program is free software; you can redistribute it and/or modify | |
861 | + * it under the terms of the GNU General Public License (Version 2) as | |
862 | + * published by the Free Software Foundation. | |
863 | + * | |
864 | + * This program is distributed in the hope that it will be useful, | |
865 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
866 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
867 | + * GNU General Public License for more details. | |
868 | + * | |
869 | + * You should have received a copy of the GNU General Public License | |
870 | + * along with this program; if not, write to the Free Software Foundation, | |
871 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
872 | + */ | |
873 | + | |
874 | +/* | |
875 | + * This file contains code to generate a firmware image for the GO7007SB | |
876 | + * encoder. Much of the firmware is read verbatim from a file, but some of | |
877 | + * it concerning bitrate control and other things that can be configured at | |
878 | + * run-time are generated dynamically. Note that the format headers | |
879 | + * generated here do not affect the functioning of the encoder; they are | |
880 | + * merely parroted back to the host at the start of each frame. | |
881 | + */ | |
882 | + | |
883 | +#include <linux/module.h> | |
884 | +#include <linux/init.h> | |
885 | +#include <linux/version.h> | |
886 | +#include <linux/time.h> | |
887 | +#include <linux/mm.h> | |
888 | +#include <linux/device.h> | |
889 | +#include <linux/i2c.h> | |
890 | +#include <linux/firmware.h> | |
891 | +#include <asm/byteorder.h> | |
892 | + | |
893 | +#include "go7007-priv.h" | |
894 | + | |
895 | +/* Constants used in the source firmware image to describe code segments */ | |
896 | + | |
897 | +#define FLAG_MODE_MJPEG (1) | |
898 | +#define FLAG_MODE_MPEG1 (1<<1) | |
899 | +#define FLAG_MODE_MPEG2 (1<<2) | |
900 | +#define FLAG_MODE_MPEG4 (1<<3) | |
901 | +#define FLAG_MODE_H263 (1<<4) | |
902 | +#define FLAG_MODE_ALL (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \ | |
903 | + FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \ | |
904 | + FLAG_MODE_H263) | |
905 | +#define FLAG_SPECIAL (1<<8) | |
906 | + | |
907 | +#define SPECIAL_FRM_HEAD 0 | |
908 | +#define SPECIAL_BRC_CTRL 1 | |
909 | +#define SPECIAL_CONFIG 2 | |
910 | +#define SPECIAL_SEQHEAD 3 | |
911 | +#define SPECIAL_AV_SYNC 4 | |
912 | +#define SPECIAL_FINAL 5 | |
913 | +#define SPECIAL_AUDIO 6 | |
914 | +#define SPECIAL_MODET 7 | |
915 | + | |
916 | +/* Little data class for creating MPEG headers bit-by-bit */ | |
917 | + | |
918 | +struct code_gen { | |
919 | + unsigned char *p; /* destination */ | |
920 | + u32 a; /* collects bits at the top of the variable */ | |
921 | + int b; /* bit position of most recently-written bit */ | |
922 | + int len; /* written out so far */ | |
923 | +}; | |
924 | + | |
925 | +#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 } | |
926 | + | |
927 | +#define CODE_ADD(name, val, length) do { \ | |
928 | + name.b -= (length); \ | |
929 | + name.a |= (val) << name.b; \ | |
930 | + while (name.b <= 24) { \ | |
931 | + *name.p = name.a >> 24; \ | |
932 | + ++name.p; \ | |
933 | + name.a <<= 8; \ | |
934 | + name.b += 8; \ | |
935 | + name.len += 8; \ | |
936 | + } \ | |
937 | +} while (0) | |
938 | + | |
939 | +#define CODE_LENGTH(name) (name.len + (32 - name.b)) | |
940 | + | |
941 | +/* Tables for creating the bitrate control data */ | |
942 | + | |
943 | +static const s16 converge_speed_ip[101] = { | |
944 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
945 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
946 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
947 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, | |
948 | + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, | |
949 | + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, | |
950 | + 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, | |
951 | + 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, | |
952 | + 19, 20, 22, 23, 25, 27, 30, 32, 35, 38, | |
953 | + 41, 45, 49, 53, 58, 63, 69, 76, 83, 91, | |
954 | + 100 | |
955 | +}; | |
956 | + | |
957 | +static const s16 converge_speed_ipb[101] = { | |
958 | + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
959 | + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
960 | + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, | |
961 | + 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, | |
962 | + 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, | |
963 | + 9, 9, 10, 10, 11, 12, 12, 13, 14, 14, | |
964 | + 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, | |
965 | + 28, 30, 32, 34, 37, 40, 42, 46, 49, 53, | |
966 | + 57, 61, 66, 71, 77, 83, 90, 97, 106, 115, | |
967 | + 125, 135, 147, 161, 175, 191, 209, 228, 249, 273, | |
968 | + 300 | |
969 | +}; | |
970 | + | |
971 | +static const s16 LAMBDA_table[4][101] = { | |
972 | + { 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, | |
973 | + 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, | |
974 | + 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, | |
975 | + 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, | |
976 | + 32, 33, 33, 34, 35, 35, 36, 37, 37, 38, | |
977 | + 39, 39, 40, 41, 42, 42, 43, 44, 45, 46, | |
978 | + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, | |
979 | + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, | |
980 | + 67, 68, 69, 70, 72, 73, 74, 76, 77, 78, | |
981 | + 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, | |
982 | + 96 | |
983 | + }, | |
984 | + { | |
985 | + 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, | |
986 | + 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, | |
987 | + 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, | |
988 | + 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, | |
989 | + 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, | |
990 | + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, | |
991 | + 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, | |
992 | + 70, 71, 72, 73, 75, 76, 78, 79, 80, 82, | |
993 | + 83, 85, 86, 88, 90, 91, 93, 95, 96, 98, | |
994 | + 100, 102, 103, 105, 107, 109, 111, 113, 115, 117, | |
995 | + 120 | |
996 | + }, | |
997 | + { | |
998 | + 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, | |
999 | + 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, | |
1000 | + 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, | |
1001 | + 41, 41, 42, 43, 44, 44, 45, 46, 47, 48, | |
1002 | + 49, 50, 50, 51, 52, 53, 54, 55, 56, 57, | |
1003 | + 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, | |
1004 | + 70, 71, 72, 74, 75, 76, 78, 79, 81, 82, | |
1005 | + 84, 85, 87, 88, 90, 92, 93, 95, 97, 98, | |
1006 | + 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, | |
1007 | + 120, 122, 124, 127, 129, 131, 134, 136, 138, 141, | |
1008 | + 144 | |
1009 | + }, | |
1010 | + { | |
1011 | + 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, | |
1012 | + 38, 38, 39, 40, 41, 41, 42, 43, 44, 44, | |
1013 | + 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, | |
1014 | + 54, 55, 56, 57, 58, 59, 60, 62, 63, 64, | |
1015 | + 65, 66, 67, 69, 70, 71, 72, 74, 75, 76, | |
1016 | + 78, 79, 81, 82, 84, 85, 87, 88, 90, 92, | |
1017 | + 93, 95, 97, 98, 100, 102, 104, 106, 108, 110, | |
1018 | + 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, | |
1019 | + 134, 136, 139, 141, 144, 146, 149, 152, 154, 157, | |
1020 | + 160, 163, 166, 169, 172, 175, 178, 181, 185, 188, | |
1021 | + 192 | |
1022 | + } | |
1023 | +}; | |
1024 | + | |
1025 | +/* MPEG blank frame generation tables */ | |
1026 | + | |
1027 | +enum mpeg_frame_type { | |
1028 | + PFRAME, | |
1029 | + BFRAME_PRE, | |
1030 | + BFRAME_POST, | |
1031 | + BFRAME_BIDIR, | |
1032 | + BFRAME_EMPTY | |
1033 | +}; | |
1034 | + | |
1035 | +static const u32 addrinctab[33][2] = { | |
1036 | + { 0x01, 1 }, { 0x03, 3 }, { 0x02, 3 }, { 0x03, 4 }, | |
1037 | + { 0x02, 4 }, { 0x03, 5 }, { 0x02, 5 }, { 0x07, 7 }, | |
1038 | + { 0x06, 7 }, { 0x0b, 8 }, { 0x0a, 8 }, { 0x09, 8 }, | |
1039 | + { 0x08, 8 }, { 0x07, 8 }, { 0x06, 8 }, { 0x17, 10 }, | |
1040 | + { 0x16, 10 }, { 0x15, 10 }, { 0x14, 10 }, { 0x13, 10 }, | |
1041 | + { 0x12, 10 }, { 0x23, 11 }, { 0x22, 11 }, { 0x21, 11 }, | |
1042 | + { 0x20, 11 }, { 0x1f, 11 }, { 0x1e, 11 }, { 0x1d, 11 }, | |
1043 | + { 0x1c, 11 }, { 0x1b, 11 }, { 0x1a, 11 }, { 0x19, 11 }, | |
1044 | + { 0x18, 11 } | |
1045 | +}; | |
1046 | + | |
1047 | +/* Standard JPEG tables */ | |
1048 | + | |
1049 | +static const u8 default_intra_quant_table[] = { | |
1050 | + 8, 16, 19, 22, 26, 27, 29, 34, | |
1051 | + 16, 16, 22, 24, 27, 29, 34, 37, | |
1052 | + 19, 22, 26, 27, 29, 34, 34, 38, | |
1053 | + 22, 22, 26, 27, 29, 34, 37, 40, | |
1054 | + 22, 26, 27, 29, 32, 35, 40, 48, | |
1055 | + 26, 27, 29, 32, 35, 40, 48, 58, | |
1056 | + 26, 27, 29, 34, 38, 46, 56, 69, | |
1057 | + 27, 29, 35, 38, 46, 56, 69, 83 | |
1058 | +}; | |
1059 | + | |
1060 | +static const u8 bits_dc_luminance[] = { | |
1061 | + 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 | |
1062 | +}; | |
1063 | + | |
1064 | +static const u8 val_dc_luminance[] = { | |
1065 | + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | |
1066 | +}; | |
1067 | + | |
1068 | +static const u8 bits_dc_chrominance[] = { | |
1069 | + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 | |
1070 | +}; | |
1071 | + | |
1072 | +static const u8 val_dc_chrominance[] = { | |
1073 | + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | |
1074 | +}; | |
1075 | + | |
1076 | +static const u8 bits_ac_luminance[] = { | |
1077 | + 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d | |
1078 | +}; | |
1079 | + | |
1080 | +static const u8 val_ac_luminance[] = { | |
1081 | + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, | |
1082 | + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, | |
1083 | + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, | |
1084 | + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, | |
1085 | + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, | |
1086 | + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, | |
1087 | + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, | |
1088 | + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, | |
1089 | + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, | |
1090 | + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, | |
1091 | + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, | |
1092 | + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, | |
1093 | + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, | |
1094 | + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | |
1095 | + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, | |
1096 | + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, | |
1097 | + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, | |
1098 | + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, | |
1099 | + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, | |
1100 | + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, | |
1101 | + 0xf9, 0xfa | |
1102 | +}; | |
1103 | + | |
1104 | +static const u8 bits_ac_chrominance[] = { | |
1105 | + 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 | |
1106 | +}; | |
1107 | + | |
1108 | +static const u8 val_ac_chrominance[] = { | |
1109 | + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, | |
1110 | + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | |
1111 | + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, | |
1112 | + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, | |
1113 | + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, | |
1114 | + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, | |
1115 | + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, | |
1116 | + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, | |
1117 | + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, | |
1118 | + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, | |
1119 | + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, | |
1120 | + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | |
1121 | + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, | |
1122 | + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, | |
1123 | + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, | |
1124 | + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, | |
1125 | + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, | |
1126 | + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, | |
1127 | + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, | |
1128 | + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, | |
1129 | + 0xf9, 0xfa | |
1130 | +}; | |
1131 | + | |
1132 | +/* Zig-zag mapping for quant table | |
1133 | + * | |
1134 | + * OK, let's do this mapping on the actual table above so it doesn't have | |
1135 | + * to be done on the fly. | |
1136 | + */ | |
1137 | +static const int zz[64] = { | |
1138 | + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, | |
1139 | + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, | |
1140 | + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, | |
1141 | + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 | |
1142 | +}; | |
1143 | + | |
1144 | +static int copy_packages(u16 *dest, u16 *src, int pkg_cnt, int space) | |
1145 | +{ | |
1146 | + int i, cnt = pkg_cnt * 32; | |
1147 | + | |
1148 | + if (space < cnt) | |
1149 | + return -1; | |
1150 | + | |
1151 | + for (i = 0; i < cnt; ++i) | |
1152 | + dest[i] = __cpu_to_le16(src[i]); | |
1153 | + | |
1154 | + return cnt; | |
1155 | +} | |
1156 | + | |
1157 | +static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q) | |
1158 | +{ | |
1159 | + int i, p = 0; | |
1160 | + | |
1161 | + buf[p++] = 0xff; | |
1162 | + buf[p++] = 0xd8; | |
1163 | + buf[p++] = 0xff; | |
1164 | + buf[p++] = 0xdb; | |
1165 | + buf[p++] = 0; | |
1166 | + buf[p++] = 2 + 65; | |
1167 | + buf[p++] = 0; | |
1168 | + buf[p++] = default_intra_quant_table[0]; | |
1169 | + for (i = 1; i < 64; ++i) | |
1170 | + /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */ | |
1171 | + buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3; | |
1172 | + buf[p++] = 0xff; | |
1173 | + buf[p++] = 0xc0; | |
1174 | + buf[p++] = 0; | |
1175 | + buf[p++] = 17; | |
1176 | + buf[p++] = 8; | |
1177 | + buf[p++] = go->height >> 8; | |
1178 | + buf[p++] = go->height & 0xff; | |
1179 | + buf[p++] = go->width >> 8; | |
1180 | + buf[p++] = go->width & 0xff; | |
1181 | + buf[p++] = 3; | |
1182 | + buf[p++] = 1; | |
1183 | + buf[p++] = 0x22; | |
1184 | + buf[p++] = 0; | |
1185 | + buf[p++] = 2; | |
1186 | + buf[p++] = 0x11; | |
1187 | + buf[p++] = 0; | |
1188 | + buf[p++] = 3; | |
1189 | + buf[p++] = 0x11; | |
1190 | + buf[p++] = 0; | |
1191 | + buf[p++] = 0xff; | |
1192 | + buf[p++] = 0xc4; | |
1193 | + buf[p++] = 418 >> 8; | |
1194 | + buf[p++] = 418 & 0xff; | |
1195 | + buf[p++] = 0x00; | |
1196 | + memcpy(buf + p, bits_dc_luminance + 1, 16); | |
1197 | + p += 16; | |
1198 | + memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance)); | |
1199 | + p += sizeof(val_dc_luminance); | |
1200 | + buf[p++] = 0x01; | |
1201 | + memcpy(buf + p, bits_dc_chrominance + 1, 16); | |
1202 | + p += 16; | |
1203 | + memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance)); | |
1204 | + p += sizeof(val_dc_chrominance); | |
1205 | + buf[p++] = 0x10; | |
1206 | + memcpy(buf + p, bits_ac_luminance + 1, 16); | |
1207 | + p += 16; | |
1208 | + memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance)); | |
1209 | + p += sizeof(val_ac_luminance); | |
1210 | + buf[p++] = 0x11; | |
1211 | + memcpy(buf + p, bits_ac_chrominance + 1, 16); | |
1212 | + p += 16; | |
1213 | + memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance)); | |
1214 | + p += sizeof(val_ac_chrominance); | |
1215 | + buf[p++] = 0xff; | |
1216 | + buf[p++] = 0xda; | |
1217 | + buf[p++] = 0; | |
1218 | + buf[p++] = 12; | |
1219 | + buf[p++] = 3; | |
1220 | + buf[p++] = 1; | |
1221 | + buf[p++] = 0x00; | |
1222 | + buf[p++] = 2; | |
1223 | + buf[p++] = 0x11; | |
1224 | + buf[p++] = 3; | |
1225 | + buf[p++] = 0x11; | |
1226 | + buf[p++] = 0; | |
1227 | + buf[p++] = 63; | |
1228 | + buf[p++] = 0; | |
1229 | + return p; | |
1230 | +} | |
1231 | + | |
1232 | +static int gen_mjpeghdr_to_package(struct go7007 *go, u16 *code, int space) | |
1233 | +{ | |
1234 | + u8 *buf; | |
1235 | + u16 mem = 0x3e00; | |
1236 | + unsigned int addr = 0x19; | |
1237 | + int size = 0, i, off = 0, chunk; | |
1238 | + | |
1239 | + buf = kmalloc(4096, GFP_KERNEL); | |
1240 | + if (buf == NULL) { | |
1241 | + printk(KERN_ERR "go7007: unable to allocate 4096 bytes for " | |
1242 | + "firmware construction\n"); | |
1243 | + return -1; | |
1244 | + } | |
1245 | + memset(buf, 0, 4096); | |
1246 | + | |
1247 | + for (i = 1; i < 32; ++i) { | |
1248 | + mjpeg_frame_header(go, buf + size, i); | |
1249 | + size += 80; | |
1250 | + } | |
1251 | + chunk = mjpeg_frame_header(go, buf + size, 1); | |
1252 | + memmove(buf + size, buf + size + 80, chunk - 80); | |
1253 | + size += chunk - 80; | |
1254 | + | |
1255 | + for (i = 0; i < size; i += chunk * 2) { | |
1256 | + if (space - off < 32) { | |
1257 | + off = -1; | |
1258 | + goto done; | |
1259 | + } | |
1260 | + | |
1261 | + code[off + 1] = __cpu_to_le16(0x8000 | mem); | |
1262 | + | |
1263 | + chunk = 28; | |
1264 | + if (mem + chunk > 0x4000) | |
1265 | + chunk = 0x4000 - mem; | |
1266 | + if (i + 2 * chunk > size) | |
1267 | + chunk = (size - i) / 2; | |
1268 | + | |
1269 | + if (chunk < 28) { | |
1270 | + code[off] = __cpu_to_le16(0x4000 | chunk); | |
1271 | + code[off + 31] = __cpu_to_le16(addr++); | |
1272 | + mem = 0x3e00; | |
1273 | + } else { | |
1274 | + code[off] = __cpu_to_le16(0x1000 | 28); | |
1275 | + code[off + 31] = 0; | |
1276 | + mem += 28; | |
1277 | + } | |
1278 | + | |
1279 | + memcpy(&code[off + 2], buf + i, chunk * 2); | |
1280 | + off += 32; | |
1281 | + } | |
1282 | +done: | |
1283 | + kfree(buf); | |
1284 | + return off; | |
1285 | +} | |
1286 | + | |
1287 | +static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf, | |
1288 | + int modulo, int pict_struct, enum mpeg_frame_type frame) | |
1289 | +{ | |
1290 | + int i, j, mb_code, mb_len; | |
1291 | + int rows = go->interlace_coding ? go->height / 32 : go->height / 16; | |
1292 | + CODE_GEN(c, buf + 6); | |
1293 | + | |
1294 | + switch (frame) { | |
1295 | + case PFRAME: | |
1296 | + mb_code = 0x1; | |
1297 | + mb_len = 3; | |
1298 | + break; | |
1299 | + case BFRAME_PRE: | |
1300 | + mb_code = 0x2; | |
1301 | + mb_len = 4; | |
1302 | + break; | |
1303 | + case BFRAME_POST: | |
1304 | + mb_code = 0x2; | |
1305 | + mb_len = 3; | |
1306 | + break; | |
1307 | + case BFRAME_BIDIR: | |
1308 | + mb_code = 0x2; | |
1309 | + mb_len = 2; | |
1310 | + break; | |
1311 | + default: /* keep the compiler happy */ | |
1312 | + mb_code = mb_len = 0; | |
1313 | + break; | |
1314 | + } | |
1315 | + | |
1316 | + CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13); | |
1317 | + CODE_ADD(c, 0xffff, 16); | |
1318 | + CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); | |
1319 | + if (frame != PFRAME) | |
1320 | + CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); | |
1321 | + else | |
1322 | + CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */ | |
1323 | + CODE_ADD(c, 0, 3); /* What is this?? */ | |
1324 | + /* Byte-align with zeros */ | |
1325 | + j = 8 - (CODE_LENGTH(c) % 8); | |
1326 | + if (j != 8) | |
1327 | + CODE_ADD(c, 0, j); | |
1328 | + | |
1329 | + if (go->format == GO7007_FORMAT_MPEG2) { | |
1330 | + CODE_ADD(c, 0x1, 24); | |
1331 | + CODE_ADD(c, 0xb5, 8); | |
1332 | + CODE_ADD(c, 0x844, 12); | |
1333 | + CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8); | |
1334 | + if (go->interlace_coding) { | |
1335 | + CODE_ADD(c, pict_struct, 4); | |
1336 | + if (go->dvd_mode) | |
1337 | + CODE_ADD(c, 0x000, 11); | |
1338 | + else | |
1339 | + CODE_ADD(c, 0x200, 11); | |
1340 | + } else { | |
1341 | + CODE_ADD(c, 0x3, 4); | |
1342 | + CODE_ADD(c, 0x20c, 11); | |
1343 | + } | |
1344 | + /* Byte-align with zeros */ | |
1345 | + j = 8 - (CODE_LENGTH(c) % 8); | |
1346 | + if (j != 8) | |
1347 | + CODE_ADD(c, 0, j); | |
1348 | + } | |
1349 | + | |
1350 | + for (i = 0; i < rows; ++i) { | |
1351 | + CODE_ADD(c, 1, 24); | |
1352 | + CODE_ADD(c, i + 1, 8); | |
1353 | + CODE_ADD(c, 0x2, 6); | |
1354 | + CODE_ADD(c, 0x1, 1); | |
1355 | + CODE_ADD(c, mb_code, mb_len); | |
1356 | + if (go->interlace_coding) { | |
1357 | + CODE_ADD(c, 0x1, 2); | |
1358 | + CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); | |
1359 | + } | |
1360 | + if (frame == BFRAME_BIDIR) { | |
1361 | + CODE_ADD(c, 0x3, 2); | |
1362 | + if (go->interlace_coding) | |
1363 | + CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); | |
1364 | + } | |
1365 | + CODE_ADD(c, 0x3, 2); | |
1366 | + for (j = (go->width >> 4) - 2; j >= 33; j -= 33) | |
1367 | + CODE_ADD(c, 0x8, 11); | |
1368 | + CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]); | |
1369 | + CODE_ADD(c, mb_code, mb_len); | |
1370 | + if (go->interlace_coding) { | |
1371 | + CODE_ADD(c, 0x1, 2); | |
1372 | + CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); | |
1373 | + } | |
1374 | + if (frame == BFRAME_BIDIR) { | |
1375 | + CODE_ADD(c, 0x3, 2); | |
1376 | + if (go->interlace_coding) | |
1377 | + CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); | |
1378 | + } | |
1379 | + CODE_ADD(c, 0x3, 2); | |
1380 | + | |
1381 | + /* Byte-align with zeros */ | |
1382 | + j = 8 - (CODE_LENGTH(c) % 8); | |
1383 | + if (j != 8) | |
1384 | + CODE_ADD(c, 0, j); | |
1385 | + } | |
1386 | + | |
1387 | + i = CODE_LENGTH(c) + 4 * 8; | |
1388 | + buf[2] = 0x00; | |
1389 | + buf[3] = 0x00; | |
1390 | + buf[4] = 0x01; | |
1391 | + buf[5] = 0x00; | |
1392 | + return i; | |
1393 | +} | |
1394 | + | |
1395 | +static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) | |
1396 | +{ | |
1397 | + int i, aspect_ratio, picture_rate; | |
1398 | + CODE_GEN(c, buf + 6); | |
1399 | + | |
1400 | + if (go->format == GO7007_FORMAT_MPEG1) { | |
1401 | + switch (go->aspect_ratio) { | |
1402 | + case GO7007_RATIO_4_3: | |
1403 | + aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; | |
1404 | + break; | |
1405 | + case GO7007_RATIO_16_9: | |
1406 | + aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; | |
1407 | + break; | |
1408 | + default: | |
1409 | + aspect_ratio = 1; | |
1410 | + break; | |
1411 | + } | |
1412 | + } else { | |
1413 | + switch (go->aspect_ratio) { | |
1414 | + case GO7007_RATIO_4_3: | |
1415 | + aspect_ratio = 2; | |
1416 | + break; | |
1417 | + case GO7007_RATIO_16_9: | |
1418 | + aspect_ratio = 3; | |
1419 | + break; | |
1420 | + default: | |
1421 | + aspect_ratio = 1; | |
1422 | + break; | |
1423 | + } | |
1424 | + } | |
1425 | + switch (go->sensor_framerate) { | |
1426 | + case 24000: | |
1427 | + picture_rate = 1; | |
1428 | + break; | |
1429 | + case 24024: | |
1430 | + picture_rate = 2; | |
1431 | + break; | |
1432 | + case 25025: | |
1433 | + picture_rate = go->interlace_coding ? 6 : 3; | |
1434 | + break; | |
1435 | + case 30000: | |
1436 | + picture_rate = go->interlace_coding ? 7 : 4; | |
1437 | + break; | |
1438 | + case 30030: | |
1439 | + picture_rate = go->interlace_coding ? 8 : 5; | |
1440 | + break; | |
1441 | + default: | |
1442 | + picture_rate = 5; /* 30 fps seems like a reasonable default */ | |
1443 | + break; | |
1444 | + } | |
1445 | + | |
1446 | + CODE_ADD(c, go->width, 12); | |
1447 | + CODE_ADD(c, go->height, 12); | |
1448 | + CODE_ADD(c, aspect_ratio, 4); | |
1449 | + CODE_ADD(c, picture_rate, 4); | |
1450 | + CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18); | |
1451 | + CODE_ADD(c, 1, 1); | |
1452 | + CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10); | |
1453 | + CODE_ADD(c, 0, 3); | |
1454 | + | |
1455 | + /* Byte-align with zeros */ | |
1456 | + i = 8 - (CODE_LENGTH(c) % 8); | |
1457 | + if (i != 8) | |
1458 | + CODE_ADD(c, 0, i); | |
1459 | + | |
1460 | + if (go->format == GO7007_FORMAT_MPEG2) { | |
1461 | + CODE_ADD(c, 0x1, 24); | |
1462 | + CODE_ADD(c, 0xb5, 8); | |
1463 | + CODE_ADD(c, 0x148, 12); | |
1464 | + if (go->interlace_coding) | |
1465 | + CODE_ADD(c, 0x20001, 20); | |
1466 | + else | |
1467 | + CODE_ADD(c, 0xa0001, 20); | |
1468 | + CODE_ADD(c, 0, 16); | |
1469 | + | |
1470 | + /* Byte-align with zeros */ | |
1471 | + i = 8 - (CODE_LENGTH(c) % 8); | |
1472 | + if (i != 8) | |
1473 | + CODE_ADD(c, 0, i); | |
1474 | + | |
1475 | + if (ext) { | |
1476 | + CODE_ADD(c, 0x1, 24); | |
1477 | + CODE_ADD(c, 0xb52, 12); | |
1478 | + CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3); | |
1479 | + CODE_ADD(c, 0x105, 9); | |
1480 | + CODE_ADD(c, 0x505, 16); | |
1481 | + CODE_ADD(c, go->width, 14); | |
1482 | + CODE_ADD(c, 1, 1); | |
1483 | + CODE_ADD(c, go->height, 14); | |
1484 | + | |
1485 | + /* Byte-align with zeros */ | |
1486 | + i = 8 - (CODE_LENGTH(c) % 8); | |
1487 | + if (i != 8) | |
1488 | + CODE_ADD(c, 0, i); | |
1489 | + } | |
1490 | + } | |
1491 | + | |
1492 | + i = CODE_LENGTH(c) + 4 * 8; | |
1493 | + buf[0] = i & 0xff; | |
1494 | + buf[1] = i >> 8; | |
1495 | + buf[2] = 0x00; | |
1496 | + buf[3] = 0x00; | |
1497 | + buf[4] = 0x01; | |
1498 | + buf[5] = 0xb3; | |
1499 | + return i; | |
1500 | +} | |
1501 | + | |
1502 | +static int gen_mpeg1hdr_to_package(struct go7007 *go, | |
1503 | + u16 *code, int space, int *framelen) | |
1504 | +{ | |
1505 | + u8 *buf; | |
1506 | + u16 mem = 0x3e00; | |
1507 | + unsigned int addr = 0x19; | |
1508 | + int i, off = 0, chunk; | |
1509 | + | |
1510 | + buf = kmalloc(5120, GFP_KERNEL); | |
1511 | + if (buf == NULL) { | |
1512 | + printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " | |
1513 | + "firmware construction\n"); | |
1514 | + return -1; | |
1515 | + } | |
1516 | + memset(buf, 0, 5120); | |
1517 | + framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME); | |
1518 | + if (go->interlace_coding) | |
1519 | + framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8, | |
1520 | + 0, 2, PFRAME); | |
1521 | + buf[0] = framelen[0] & 0xff; | |
1522 | + buf[1] = framelen[0] >> 8; | |
1523 | + i = 368; | |
1524 | + framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE); | |
1525 | + if (go->interlace_coding) | |
1526 | + framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8, | |
1527 | + 0, 2, BFRAME_PRE); | |
1528 | + buf[i] = framelen[1] & 0xff; | |
1529 | + buf[i + 1] = framelen[1] >> 8; | |
1530 | + i += 1632; | |
1531 | + framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST); | |
1532 | + if (go->interlace_coding) | |
1533 | + framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8, | |
1534 | + 0, 2, BFRAME_POST); | |
1535 | + buf[i] = framelen[2] & 0xff; | |
1536 | + buf[i + 1] = framelen[2] >> 8; | |
1537 | + i += 1432; | |
1538 | + framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR); | |
1539 | + if (go->interlace_coding) | |
1540 | + framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8, | |
1541 | + 0, 2, BFRAME_BIDIR); | |
1542 | + buf[i] = framelen[3] & 0xff; | |
1543 | + buf[i + 1] = framelen[3] >> 8; | |
1544 | + i += 1632 + 16; | |
1545 | + mpeg1_sequence_header(go, buf + i, 0); | |
1546 | + i += 40; | |
1547 | + for (i = 0; i < 5120; i += chunk * 2) { | |
1548 | + if (space - off < 32) { | |
1549 | + off = -1; | |
1550 | + goto done; | |
1551 | + } | |
1552 | + | |
1553 | + code[off + 1] = __cpu_to_le16(0x8000 | mem); | |
1554 | + | |
1555 | + chunk = 28; | |
1556 | + if (mem + chunk > 0x4000) | |
1557 | + chunk = 0x4000 - mem; | |
1558 | + if (i + 2 * chunk > 5120) | |
1559 | + chunk = (5120 - i) / 2; | |
1560 | + | |
1561 | + if (chunk < 28) { | |
1562 | + code[off] = __cpu_to_le16(0x4000 | chunk); | |
1563 | + code[off + 31] = __cpu_to_le16(addr); | |
1564 | + if (mem + chunk == 0x4000) { | |
1565 | + mem = 0x3e00; | |
1566 | + ++addr; | |
1567 | + } | |
1568 | + } else { | |
1569 | + code[off] = __cpu_to_le16(0x1000 | 28); | |
1570 | + code[off + 31] = 0; | |
1571 | + mem += 28; | |
1572 | + } | |
1573 | + | |
1574 | + memcpy(&code[off + 2], buf + i, chunk * 2); | |
1575 | + off += 32; | |
1576 | + } | |
1577 | +done: | |
1578 | + kfree(buf); | |
1579 | + return off; | |
1580 | +} | |
1581 | + | |
1582 | +static int vti_bitlen(struct go7007 *go) | |
1583 | +{ | |
1584 | + unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale; | |
1585 | + | |
1586 | + for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i); | |
1587 | + return i + 1; | |
1588 | +} | |
1589 | + | |
1590 | +static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf, | |
1591 | + int modulo, enum mpeg_frame_type frame) | |
1592 | +{ | |
1593 | + int i; | |
1594 | + CODE_GEN(c, buf + 6); | |
1595 | + int mb_count = (go->width >> 4) * (go->height >> 4); | |
1596 | + | |
1597 | + CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2); | |
1598 | + if (modulo) | |
1599 | + CODE_ADD(c, 0x1, 1); | |
1600 | + CODE_ADD(c, 0x1, 2); | |
1601 | + CODE_ADD(c, 0, vti_bitlen(go)); | |
1602 | + CODE_ADD(c, 0x3, 2); | |
1603 | + if (frame == PFRAME) | |
1604 | + CODE_ADD(c, 0, 1); | |
1605 | + CODE_ADD(c, 0xc, 11); | |
1606 | + if (frame != PFRAME) | |
1607 | + CODE_ADD(c, 0x4, 3); | |
1608 | + if (frame != BFRAME_EMPTY) { | |
1609 | + for (i = 0; i < mb_count; ++i) { | |
1610 | + switch (frame) { | |
1611 | + case PFRAME: | |
1612 | + CODE_ADD(c, 0x1, 1); | |
1613 | + break; | |
1614 | + case BFRAME_PRE: | |
1615 | + CODE_ADD(c, 0x47, 8); | |
1616 | + break; | |
1617 | + case BFRAME_POST: | |
1618 | + CODE_ADD(c, 0x27, 7); | |
1619 | + break; | |
1620 | + case BFRAME_BIDIR: | |
1621 | + CODE_ADD(c, 0x5f, 8); | |
1622 | + break; | |
1623 | + case BFRAME_EMPTY: /* keep compiler quiet */ | |
1624 | + break; | |
1625 | + } | |
1626 | + } | |
1627 | + } | |
1628 | + | |
1629 | + /* Byte-align with a zero followed by ones */ | |
1630 | + i = 8 - (CODE_LENGTH(c) % 8); | |
1631 | + CODE_ADD(c, 0, 1); | |
1632 | + CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); | |
1633 | + | |
1634 | + i = CODE_LENGTH(c) + 4 * 8; | |
1635 | + buf[0] = i & 0xff; | |
1636 | + buf[1] = i >> 8; | |
1637 | + buf[2] = 0x00; | |
1638 | + buf[3] = 0x00; | |
1639 | + buf[4] = 0x01; | |
1640 | + buf[5] = 0xb6; | |
1641 | + return i; | |
1642 | +} | |
1643 | + | |
1644 | +static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext) | |
1645 | +{ | |
1646 | + const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali, | |
1647 | + 0x00, 0x00, 0x01, 0xb5, 0x09, | |
1648 | + 0x00, 0x00, 0x01, 0x00, | |
1649 | + 0x00, 0x00, 0x01, 0x20, }; | |
1650 | + int i, aspect_ratio; | |
1651 | + int fps = go->sensor_framerate / go->fps_scale; | |
1652 | + CODE_GEN(c, buf + 2 + sizeof(head)); | |
1653 | + | |
1654 | + switch (go->aspect_ratio) { | |
1655 | + case GO7007_RATIO_4_3: | |
1656 | + aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; | |
1657 | + break; | |
1658 | + case GO7007_RATIO_16_9: | |
1659 | + aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; | |
1660 | + break; | |
1661 | + default: | |
1662 | + aspect_ratio = 1; | |
1663 | + break; | |
1664 | + } | |
1665 | + | |
1666 | + memcpy(buf + 2, head, sizeof(head)); | |
1667 | + CODE_ADD(c, 0x191, 17); | |
1668 | + CODE_ADD(c, aspect_ratio, 4); | |
1669 | + CODE_ADD(c, 0x1, 4); | |
1670 | + CODE_ADD(c, fps, 16); | |
1671 | + CODE_ADD(c, 0x3, 2); | |
1672 | + CODE_ADD(c, 1001, vti_bitlen(go)); | |
1673 | + CODE_ADD(c, 1, 1); | |
1674 | + CODE_ADD(c, go->width, 13); | |
1675 | + CODE_ADD(c, 1, 1); | |
1676 | + CODE_ADD(c, go->height, 13); | |
1677 | + CODE_ADD(c, 0x2830, 14); | |
1678 | + | |
1679 | + /* Byte-align */ | |
1680 | + i = 8 - (CODE_LENGTH(c) % 8); | |
1681 | + CODE_ADD(c, 0, 1); | |
1682 | + CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); | |
1683 | + | |
1684 | + i = CODE_LENGTH(c) + sizeof(head) * 8; | |
1685 | + buf[0] = i & 0xff; | |
1686 | + buf[1] = i >> 8; | |
1687 | + return i; | |
1688 | +} | |
1689 | + | |
1690 | +static int gen_mpeg4hdr_to_package(struct go7007 *go, | |
1691 | + u16 *code, int space, int *framelen) | |
1692 | +{ | |
1693 | + u8 *buf; | |
1694 | + u16 mem = 0x3e00; | |
1695 | + unsigned int addr = 0x19; | |
1696 | + int i, off = 0, chunk; | |
1697 | + | |
1698 | + buf = kmalloc(5120, GFP_KERNEL); | |
1699 | + if (buf == NULL) { | |
1700 | + printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " | |
1701 | + "firmware construction\n"); | |
1702 | + return -1; | |
1703 | + } | |
1704 | + memset(buf, 0, 5120); | |
1705 | + framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME); | |
1706 | + i = 368; | |
1707 | + framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE); | |
1708 | + i += 1632; | |
1709 | + framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST); | |
1710 | + i += 1432; | |
1711 | + framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR); | |
1712 | + i += 1632; | |
1713 | + mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY); | |
1714 | + i += 16; | |
1715 | + mpeg4_sequence_header(go, buf + i, 0); | |
1716 | + i += 40; | |
1717 | + for (i = 0; i < 5120; i += chunk * 2) { | |
1718 | + if (space - off < 32) { | |
1719 | + off = -1; | |
1720 | + goto done; | |
1721 | + } | |
1722 | + | |
1723 | + code[off + 1] = __cpu_to_le16(0x8000 | mem); | |
1724 | + | |
1725 | + chunk = 28; | |
1726 | + if (mem + chunk > 0x4000) | |
1727 | + chunk = 0x4000 - mem; | |
1728 | + if (i + 2 * chunk > 5120) | |
1729 | + chunk = (5120 - i) / 2; | |
1730 | + | |
1731 | + if (chunk < 28) { | |
1732 | + code[off] = __cpu_to_le16(0x4000 | chunk); | |
1733 | + code[off + 31] = __cpu_to_le16(addr); | |
1734 | + if (mem + chunk == 0x4000) { | |
1735 | + mem = 0x3e00; | |
1736 | + ++addr; | |
1737 | + } | |
1738 | + } else { | |
1739 | + code[off] = __cpu_to_le16(0x1000 | 28); | |
1740 | + code[off + 31] = 0; | |
1741 | + mem += 28; | |
1742 | + } | |
1743 | + | |
1744 | + memcpy(&code[off + 2], buf + i, chunk * 2); | |
1745 | + off += 32; | |
1746 | + } | |
1747 | + mem = 0x3e00; | |
1748 | + addr = go->ipb ? 0x14f9 : 0x0af9; | |
1749 | + memset(buf, 0, 5120); | |
1750 | + framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME); | |
1751 | + i = 368; | |
1752 | + framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE); | |
1753 | + i += 1632; | |
1754 | + framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST); | |
1755 | + i += 1432; | |
1756 | + framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR); | |
1757 | + i += 1632; | |
1758 | + mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY); | |
1759 | + i += 16; | |
1760 | + for (i = 0; i < 5120; i += chunk * 2) { | |
1761 | + if (space - off < 32) { | |
1762 | + off = -1; | |
1763 | + goto done; | |
1764 | + } | |
1765 | + | |
1766 | + code[off + 1] = __cpu_to_le16(0x8000 | mem); | |
1767 | + | |
1768 | + chunk = 28; | |
1769 | + if (mem + chunk > 0x4000) | |
1770 | + chunk = 0x4000 - mem; | |
1771 | + if (i + 2 * chunk > 5120) | |
1772 | + chunk = (5120 - i) / 2; | |
1773 | + | |
1774 | + if (chunk < 28) { | |
1775 | + code[off] = __cpu_to_le16(0x4000 | chunk); | |
1776 | + code[off + 31] = __cpu_to_le16(addr); | |
1777 | + if (mem + chunk == 0x4000) { | |
1778 | + mem = 0x3e00; | |
1779 | + ++addr; | |
1780 | + } | |
1781 | + } else { | |
1782 | + code[off] = __cpu_to_le16(0x1000 | 28); | |
1783 | + code[off + 31] = 0; | |
1784 | + mem += 28; | |
1785 | + } | |
1786 | + | |
1787 | + memcpy(&code[off + 2], buf + i, chunk * 2); | |
1788 | + off += 32; | |
1789 | + } | |
1790 | +done: | |
1791 | + kfree(buf); | |
1792 | + return off; | |
1793 | +} | |
1794 | + | |
1795 | +static int brctrl_to_package(struct go7007 *go, | |
1796 | + u16 *code, int space, int *framelen) | |
1797 | +{ | |
1798 | + int converge_speed = 0; | |
1799 | + int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ? | |
1800 | + 100 : 0; | |
1801 | + int peak_rate = 6 * go->bitrate / 5; | |
1802 | + int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ? | |
1803 | + go->bitrate : | |
1804 | + (go->dvd_mode ? 900000 : peak_rate); | |
1805 | + int fps = go->sensor_framerate / go->fps_scale; | |
1806 | + int q = 0; | |
1807 | + /* Bizarre math below depends on rounding errors in division */ | |
1808 | + u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps; | |
1809 | + u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps; | |
1810 | + u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000); | |
1811 | + u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32); | |
1812 | + u32 cplx[] = { | |
1813 | + q > 0 ? sgop_expt_addr * q : | |
1814 | + 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, | |
1815 | + q > 0 ? sgop_expt_addr * q : | |
1816 | + 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, | |
1817 | + q > 0 ? sgop_expt_addr * q : | |
1818 | + 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, | |
1819 | + q > 0 ? sgop_expt_addr * q : | |
1820 | + 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, | |
1821 | + }; | |
1822 | + u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr; | |
1823 | + u16 pack[] = { | |
1824 | + 0x200e, 0x0000, | |
1825 | + 0xBF20, go->ipb ? converge_speed_ipb[converge_speed] | |
1826 | + : converge_speed_ip[converge_speed], | |
1827 | + 0xBF21, go->ipb ? 2 : 0, | |
1828 | + 0xBF22, go->ipb ? LAMBDA_table[0][lambda / 2 + 50] | |
1829 | + : 32767, | |
1830 | + 0xBF23, go->ipb ? LAMBDA_table[1][lambda] : 32767, | |
1831 | + 0xBF24, 32767, | |
1832 | + 0xBF25, lambda > 99 ? 32767 : LAMBDA_table[3][lambda], | |
1833 | + 0xBF26, sgop_expt_addr & 0x0000FFFF, | |
1834 | + 0xBF27, sgop_expt_addr >> 16, | |
1835 | + 0xBF28, sgop_peak_addr & 0x0000FFFF, | |
1836 | + 0xBF29, sgop_peak_addr >> 16, | |
1837 | + 0xBF2A, vbv_alert_addr & 0x0000FFFF, | |
1838 | + 0xBF2B, vbv_alert_addr >> 16, | |
1839 | + 0xBF2C, 0, | |
1840 | + 0xBF2D, 0, | |
1841 | + 0, 0, | |
1842 | + | |
1843 | + 0x200e, 0x0000, | |
1844 | + 0xBF2E, vbv_alert_addr & 0x0000FFFF, | |
1845 | + 0xBF2F, vbv_alert_addr >> 16, | |
1846 | + 0xBF30, cplx[0] & 0x0000FFFF, | |
1847 | + 0xBF31, cplx[0] >> 16, | |
1848 | + 0xBF32, cplx[1] & 0x0000FFFF, | |
1849 | + 0xBF33, cplx[1] >> 16, | |
1850 | + 0xBF34, cplx[2] & 0x0000FFFF, | |
1851 | + 0xBF35, cplx[2] >> 16, | |
1852 | + 0xBF36, cplx[3] & 0x0000FFFF, | |
1853 | + 0xBF37, cplx[3] >> 16, | |
1854 | + 0xBF38, 0, | |
1855 | + 0xBF39, 0, | |
1856 | + 0xBF3A, total_expt_addr & 0x0000FFFF, | |
1857 | + 0xBF3B, total_expt_addr >> 16, | |
1858 | + 0, 0, | |
1859 | + | |
1860 | + 0x200e, 0x0000, | |
1861 | + 0xBF3C, total_expt_addr & 0x0000FFFF, | |
1862 | + 0xBF3D, total_expt_addr >> 16, | |
1863 | + 0xBF3E, 0, | |
1864 | + 0xBF3F, 0, | |
1865 | + 0xBF48, 0, | |
1866 | + 0xBF49, 0, | |
1867 | + 0xBF4A, calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q), | |
1868 | + 0xBF4B, 4, | |
1869 | + 0xBF4C, 0, | |
1870 | + 0xBF4D, 0, | |
1871 | + 0xBF4E, 0, | |
1872 | + 0xBF4F, 0, | |
1873 | + 0xBF50, 0, | |
1874 | + 0xBF51, 0, | |
1875 | + 0, 0, | |
1876 | + | |
1877 | + 0x200e, 0x0000, | |
1878 | + 0xBF40, sgop_expt_addr & 0x0000FFFF, | |
1879 | + 0xBF41, sgop_expt_addr >> 16, | |
1880 | + 0xBF42, 0, | |
1881 | + 0xBF43, 0, | |
1882 | + 0xBF44, 0, | |
1883 | + 0xBF45, 0, | |
1884 | + 0xBF46, (go->width >> 4) * (go->height >> 4), | |
1885 | + 0xBF47, 0, | |
1886 | + 0xBF64, 0, | |
1887 | + 0xBF65, 0, | |
1888 | + 0xBF18, framelen[4], | |
1889 | + 0xBF19, framelen[5], | |
1890 | + 0xBF1A, framelen[6], | |
1891 | + 0xBF1B, framelen[7], | |
1892 | + 0, 0, | |
1893 | + | |
1894 | +#if 0 /* Remove once we don't care about matching */ | |
1895 | + 0x200e, 0x0000, | |
1896 | + 0xBF56, 4, | |
1897 | + 0xBF57, 0, | |
1898 | + 0xBF58, 5, | |
1899 | + 0xBF59, 0, | |
1900 | + 0xBF5A, 6, | |
1901 | + 0xBF5B, 0, | |
1902 | + 0xBF5C, 8, | |
1903 | + 0xBF5D, 0, | |
1904 | + 0xBF5E, 1, | |
1905 | + 0xBF5F, 0, | |
1906 | + 0xBF60, 1, | |
1907 | + 0xBF61, 0, | |
1908 | + 0xBF62, 0, | |
1909 | + 0xBF63, 0, | |
1910 | + 0, 0, | |
1911 | +#else | |
1912 | + 0x2008, 0x0000, | |
1913 | + 0xBF56, 4, | |
1914 | + 0xBF57, 0, | |
1915 | + 0xBF58, 5, | |
1916 | + 0xBF59, 0, | |
1917 | + 0xBF5A, 6, | |
1918 | + 0xBF5B, 0, | |
1919 | + 0xBF5C, 8, | |
1920 | + 0xBF5D, 0, | |
1921 | + 0, 0, | |
1922 | + 0, 0, | |
1923 | + 0, 0, | |
1924 | + 0, 0, | |
1925 | + 0, 0, | |
1926 | + 0, 0, | |
1927 | + 0, 0, | |
1928 | +#endif | |
1929 | + | |
1930 | + 0x200e, 0x0000, | |
1931 | + 0xBF10, 0, | |
1932 | + 0xBF11, 0, | |
1933 | + 0xBF12, 0, | |
1934 | + 0xBF13, 0, | |
1935 | + 0xBF14, 0, | |
1936 | + 0xBF15, 0, | |
1937 | + 0xBF16, 0, | |
1938 | + 0xBF17, 0, | |
1939 | + 0xBF7E, 0, | |
1940 | + 0xBF7F, 1, | |
1941 | + 0xBF52, framelen[0], | |
1942 | + 0xBF53, framelen[1], | |
1943 | + 0xBF54, framelen[2], | |
1944 | + 0xBF55, framelen[3], | |
1945 | + 0, 0, | |
1946 | + }; | |
1947 | + | |
1948 | + return copy_packages(code, pack, 6, space); | |
1949 | +} | |
1950 | + | |
1951 | +static int config_package(struct go7007 *go, u16 *code, int space) | |
1952 | +{ | |
1953 | + int fps = go->sensor_framerate / go->fps_scale / 1000; | |
1954 | + int rows = go->interlace_coding ? go->height / 32 : go->height / 16; | |
1955 | + int brc_window_size = fps; | |
1956 | + int q_min = 2, q_max = 31; | |
1957 | + int THACCoeffSet0 = 0; | |
1958 | + u16 pack[] = { | |
1959 | + 0x200e, 0x0000, | |
1960 | + 0xc002, 0x14b4, | |
1961 | + 0xc003, 0x28b4, | |
1962 | + 0xc004, 0x3c5a, | |
1963 | + 0xdc05, 0x2a77, | |
1964 | + 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 : | |
1965 | + (go->format == GO7007_FORMAT_H263 ? 0 : 1), | |
1966 | + 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 : | |
1967 | + (go->format == GO7007_FORMAT_H263 ? 0x61 : | |
1968 | + 0xd3), | |
1969 | + 0xc780, 0x0140, | |
1970 | + 0xe009, 0x0001, | |
1971 | + 0xc60f, 0x0008, | |
1972 | + 0xd4ff, 0x0002, | |
1973 | + 0xe403, 2340, | |
1974 | + 0xe406, 75, | |
1975 | + 0xd411, 0x0001, | |
1976 | + 0xd410, 0xa1d6, | |
1977 | + 0x0001, 0x2801, | |
1978 | + | |
1979 | + 0x200d, 0x0000, | |
1980 | + 0xe402, 0x018b, | |
1981 | + 0xe401, 0x8b01, | |
1982 | + 0xd472, (go->board_info->sensor_flags & | |
1983 | + GO7007_SENSOR_TV) && | |
1984 | + (!go->interlace_coding) ? | |
1985 | + 0x01b0 : 0x0170, | |
1986 | + 0xd475, (go->board_info->sensor_flags & | |
1987 | + GO7007_SENSOR_TV) && | |
1988 | + (!go->interlace_coding) ? | |
1989 | + 0x0008 : 0x0009, | |
1990 | + 0xc404, go->interlace_coding ? 0x44 : | |
1991 | + (go->format == GO7007_FORMAT_MPEG4 ? 0x11 : | |
1992 | + (go->format == GO7007_FORMAT_MPEG1 ? 0x02 : | |
1993 | + (go->format == GO7007_FORMAT_MPEG2 ? 0x04 : | |
1994 | + (go->format == GO7007_FORMAT_H263 ? 0x08 : | |
1995 | + 0x20)))), | |
1996 | + 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 : | |
1997 | + (go->format == GO7007_FORMAT_MPEG1 ? 1 : | |
1998 | + (go->format == GO7007_FORMAT_MPEG2 ? 2 : | |
1999 | + (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) | | |
2000 | + ((go->repeat_seqhead ? 1 : 0) << 6) | | |
2001 | + ((go->dvd_mode ? 1 : 0) << 9) | | |
2002 | + ((go->gop_header_enable ? 1 : 0) << 10), | |
2003 | + 0xbf0b, 0, | |
2004 | + 0xdd5a, go->ipb ? 0x14 : 0x0a, | |
2005 | + 0xbf0c, 0, | |
2006 | + 0xbf0d, 0, | |
2007 | + 0xc683, THACCoeffSet0, | |
2008 | + 0xc40a, (go->width << 4) | rows, | |
2009 | + 0xe01a, go->board_info->hpi_buffer_cap, | |
2010 | + 0, 0, | |
2011 | + 0, 0, | |
2012 | + | |
2013 | + 0x2008, 0, | |
2014 | + 0xe402, 0x88, | |
2015 | + 0xe401, 0x8f01, | |
2016 | + 0xbf6a, 0, | |
2017 | + 0xbf6b, 0, | |
2018 | + 0xbf6c, 0, | |
2019 | + 0xbf6d, 0, | |
2020 | + 0xbf6e, 0, | |
2021 | + 0xbf6f, 0, | |
2022 | + 0, 0, | |
2023 | + 0, 0, | |
2024 | + 0, 0, | |
2025 | + 0, 0, | |
2026 | + 0, 0, | |
2027 | + 0, 0, | |
2028 | + 0, 0, | |
2029 | + | |
2030 | + 0x200e, 0, | |
2031 | + 0xbf66, brc_window_size, | |
2032 | + 0xbf67, 0, | |
2033 | + 0xbf68, q_min, | |
2034 | + 0xbf69, q_max, | |
2035 | + 0xbfe0, 0, | |
2036 | + 0xbfe1, 0, | |
2037 | + 0xbfe2, 0, | |
2038 | + 0xbfe3, go->ipb ? 3 : 1, | |
2039 | + 0xc031, go->board_info->sensor_flags & | |
2040 | + GO7007_SENSOR_VBI ? 1 : 0, | |
2041 | + 0xc01c, 0x1f, | |
2042 | + 0xdd8c, 0x15, | |
2043 | + 0xdd94, 0x15, | |
2044 | + 0xdd88, go->ipb ? 0x1401 : 0x0a01, | |
2045 | + 0xdd90, go->ipb ? 0x1401 : 0x0a01, | |
2046 | + 0, 0, | |
2047 | + | |
2048 | + 0x200e, 0, | |
2049 | + 0xbfe4, 0, | |
2050 | + 0xbfe5, 0, | |
2051 | + 0xbfe6, 0, | |
2052 | + 0xbfe7, fps << 8, | |
2053 | + 0xbfe8, 0x3a00, | |
2054 | + 0xbfe9, 0, | |
2055 | + 0xbfea, 0, | |
2056 | + 0xbfeb, 0, | |
2057 | + 0xbfec, (go->interlace_coding ? 1 << 15 : 0) | | |
2058 | + (go->modet_enable ? 0xa : 0) | | |
2059 | + (go->board_info->sensor_flags & | |
2060 | + GO7007_SENSOR_VBI ? 1 : 0), | |
2061 | + 0xbfed, 0, | |
2062 | + 0xbfee, 0, | |
2063 | + 0xbfef, 0, | |
2064 | + 0xbff0, go->board_info->sensor_flags & | |
2065 | + GO7007_SENSOR_TV ? 0xf060 : 0xb060, | |
2066 | + 0xbff1, 0, | |
2067 | + 0, 0, | |
2068 | + }; | |
2069 | + | |
2070 | + return copy_packages(code, pack, 5, space); | |
2071 | +} | |
2072 | + | |
2073 | +static int seqhead_to_package(struct go7007 *go, u16 *code, int space, | |
2074 | + int (*sequence_header_func)(struct go7007 *go, | |
2075 | + unsigned char *buf, int ext)) | |
2076 | +{ | |
2077 | + int vop_time_increment_bitlength = vti_bitlen(go); | |
2078 | + int fps = go->sensor_framerate / go->fps_scale * | |
2079 | + (go->interlace_coding ? 2 : 1); | |
2080 | + unsigned char buf[40] = { }; | |
2081 | + int len = sequence_header_func(go, buf, 1); | |
2082 | + u16 pack[] = { | |
2083 | + 0x2006, 0, | |
2084 | + 0xbf08, fps, | |
2085 | + 0xbf09, 0, | |
2086 | + 0xbff2, vop_time_increment_bitlength, | |
2087 | + 0xbff3, (1 << vop_time_increment_bitlength) - 1, | |
2088 | + 0xbfe6, 0, | |
2089 | + 0xbfe7, (fps / 1000) << 8, | |
2090 | + 0, 0, | |
2091 | + 0, 0, | |
2092 | + 0, 0, | |
2093 | + 0, 0, | |
2094 | + 0, 0, | |
2095 | + 0, 0, | |
2096 | + 0, 0, | |
2097 | + 0, 0, | |
2098 | + 0, 0, | |
2099 | + | |
2100 | + 0x2007, 0, | |
2101 | + 0xc800, buf[2] << 8 | buf[3], | |
2102 | + 0xc801, buf[4] << 8 | buf[5], | |
2103 | + 0xc802, buf[6] << 8 | buf[7], | |
2104 | + 0xc803, buf[8] << 8 | buf[9], | |
2105 | + 0xc406, 64, | |
2106 | + 0xc407, len - 64, | |
2107 | + 0xc61b, 1, | |
2108 | + 0, 0, | |
2109 | + 0, 0, | |
2110 | + 0, 0, | |
2111 | + 0, 0, | |
2112 | + 0, 0, | |
2113 | + 0, 0, | |
2114 | + 0, 0, | |
2115 | + 0, 0, | |
2116 | + | |
2117 | + 0x200e, 0, | |
2118 | + 0xc808, buf[10] << 8 | buf[11], | |
2119 | + 0xc809, buf[12] << 8 | buf[13], | |
2120 | + 0xc80a, buf[14] << 8 | buf[15], | |
2121 | + 0xc80b, buf[16] << 8 | buf[17], | |
2122 | + 0xc80c, buf[18] << 8 | buf[19], | |
2123 | + 0xc80d, buf[20] << 8 | buf[21], | |
2124 | + 0xc80e, buf[22] << 8 | buf[23], | |
2125 | + 0xc80f, buf[24] << 8 | buf[25], | |
2126 | + 0xc810, buf[26] << 8 | buf[27], | |
2127 | + 0xc811, buf[28] << 8 | buf[29], | |
2128 | + 0xc812, buf[30] << 8 | buf[31], | |
2129 | + 0xc813, buf[32] << 8 | buf[33], | |
2130 | + 0xc814, buf[34] << 8 | buf[35], | |
2131 | + 0xc815, buf[36] << 8 | buf[37], | |
2132 | + 0, 0, | |
2133 | + 0, 0, | |
2134 | + 0, 0, | |
2135 | + }; | |
2136 | + | |
2137 | + return copy_packages(code, pack, 3, space); | |
2138 | +} | |
2139 | + | |
2140 | +static int relative_prime(int big, int little) | |
2141 | +{ | |
2142 | + int remainder; | |
2143 | + | |
2144 | + while (little != 0) { | |
2145 | + remainder = big % little; | |
2146 | + big = little; | |
2147 | + little = remainder; | |
2148 | + } | |
2149 | + return big; | |
2150 | +} | |
2151 | + | |
2152 | +static int avsync_to_package(struct go7007 *go, u16 *code, int space) | |
2153 | +{ | |
2154 | + int arate = go->board_info->audio_rate * 1001 * go->fps_scale; | |
2155 | + int ratio = arate / go->sensor_framerate; | |
2156 | + int adjratio = ratio * 215 / 100; | |
2157 | + int rprime = relative_prime(go->sensor_framerate, | |
2158 | + arate % go->sensor_framerate); | |
2159 | + int f1 = (arate % go->sensor_framerate) / rprime; | |
2160 | + int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime; | |
2161 | + u16 pack[] = { | |
2162 | + 0x200e, 0, | |
2163 | + 0xbf98, (u16)((-adjratio) & 0xffff), | |
2164 | + 0xbf99, (u16)((-adjratio) >> 16), | |
2165 | + 0xbf92, 0, | |
2166 | + 0xbf93, 0, | |
2167 | + 0xbff4, f1 > f2 ? f1 : f2, | |
2168 | + 0xbff5, f1 < f2 ? f1 : f2, | |
2169 | + 0xbff6, f1 < f2 ? ratio : ratio + 1, | |
2170 | + 0xbff7, f1 > f2 ? ratio : ratio + 1, | |
2171 | + 0xbff8, 0, | |
2172 | + 0xbff9, 0, | |
2173 | + 0xbffa, adjratio & 0xffff, | |
2174 | + 0xbffb, adjratio >> 16, | |
2175 | + 0xbf94, 0, | |
2176 | + 0xbf95, 0, | |
2177 | + 0, 0, | |
2178 | + }; | |
2179 | + | |
2180 | + return copy_packages(code, pack, 1, space); | |
2181 | +} | |
2182 | + | |
2183 | +static int final_package(struct go7007 *go, u16 *code, int space) | |
2184 | +{ | |
2185 | + int rows = go->interlace_coding ? go->height / 32 : go->height / 16; | |
2186 | + u16 pack[] = { | |
2187 | + 0x8000, | |
2188 | + 0, | |
2189 | + 0, | |
2190 | + 0, | |
2191 | + 0, | |
2192 | + 0, | |
2193 | + 0, | |
2194 | + 2, | |
2195 | + ((go->board_info->sensor_flags & GO7007_SENSOR_TV) && | |
2196 | + (!go->interlace_coding) ? | |
2197 | + (1 << 14) | (1 << 9) : 0) | | |
2198 | + ((go->encoder_subsample ? 1 : 0) << 8) | | |
2199 | + (go->board_info->sensor_flags & | |
2200 | + GO7007_SENSOR_CONFIG_MASK), | |
2201 | + ((go->encoder_v_halve ? 1 : 0) << 14) | | |
2202 | + (go->encoder_v_halve ? rows << 9 : rows << 8) | | |
2203 | + (go->encoder_h_halve ? 1 << 6 : 0) | | |
2204 | + (go->encoder_h_halve ? go->width >> 3 : go->width >> 4), | |
2205 | + (1 << 15) | (go->encoder_v_offset << 6) | | |
2206 | + (1 << 7) | (go->encoder_h_offset >> 2), | |
2207 | + (1 << 6), | |
2208 | + 0, | |
2209 | + 0, | |
2210 | + ((go->fps_scale - 1) << 8) | | |
2211 | + (go->board_info->sensor_flags & GO7007_SENSOR_TV ? | |
2212 | + (1 << 7) : 0) | | |
2213 | + 0x41, | |
2214 | + go->ipb ? 0xd4c : 0x36b, | |
2215 | + (rows << 8) | (go->width >> 4), | |
2216 | + go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0, | |
2217 | + (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) | | |
2218 | + ((go->closed_gop ? 1 : 0) << 12) | | |
2219 | + ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) | | |
2220 | + /* (1 << 9) | */ | |
2221 | + ((go->ipb ? 3 : 0) << 7) | | |
2222 | + ((go->modet_enable ? 1 : 0) << 2) | | |
2223 | + ((go->dvd_mode ? 1 : 0) << 1) | 1, | |
2224 | + (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 : | |
2225 | + (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 : | |
2226 | + (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 : | |
2227 | + (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 : | |
2228 | + (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))), | |
2229 | + go->ipb ? 0x1f15 : 0x1f0b, | |
2230 | + go->ipb ? 0x0015 : 0x000b, | |
2231 | + go->ipb ? 0xa800 : 0x5800, | |
2232 | + 0xffff, | |
2233 | + 0x0020 + 0x034b * 0, | |
2234 | + 0x0020 + 0x034b * 1, | |
2235 | + 0x0020 + 0x034b * 2, | |
2236 | + 0x0020 + 0x034b * 3, | |
2237 | + 0x0020 + 0x034b * 4, | |
2238 | + 0x0020 + 0x034b * 5, | |
2239 | + go->ipb ? (go->gop_size / 3) : go->gop_size, | |
2240 | + (go->height >> 4) * (go->width >> 4) * 110 / 100, | |
2241 | + }; | |
2242 | + | |
2243 | + return copy_packages(code, pack, 1, space); | |
2244 | +} | |
2245 | + | |
2246 | +static int audio_to_package(struct go7007 *go, u16 *code, int space) | |
2247 | +{ | |
2248 | + int clock_config = ((go->board_info->audio_flags & | |
2249 | + GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) | | |
2250 | + ((go->board_info->audio_flags & | |
2251 | + GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) | | |
2252 | + (((go->board_info->audio_bclk_div / 4) - 1) << 4) | | |
2253 | + (go->board_info->audio_main_div - 1); | |
2254 | + u16 pack[] = { | |
2255 | + 0x200d, 0, | |
2256 | + 0x9002, 0, | |
2257 | + 0x9002, 0, | |
2258 | + 0x9031, 0, | |
2259 | + 0x9032, 0, | |
2260 | + 0x9033, 0, | |
2261 | + 0x9034, 0, | |
2262 | + 0x9035, 0, | |
2263 | + 0x9036, 0, | |
2264 | + 0x9037, 0, | |
2265 | + 0x9040, 0, | |
2266 | + 0x9000, clock_config, | |
2267 | + 0x9001, (go->board_info->audio_flags & 0xffff) | | |
2268 | + (1 << 9), | |
2269 | + 0x9000, ((go->board_info->audio_flags & | |
2270 | + GO7007_AUDIO_I2S_MASTER ? | |
2271 | + 1 : 0) << 10) | | |
2272 | + clock_config, | |
2273 | + 0, 0, | |
2274 | + 0, 0, | |
2275 | + 0x2005, 0, | |
2276 | + 0x9041, 0, | |
2277 | + 0x9042, 256, | |
2278 | + 0x9043, 0, | |
2279 | + 0x9044, 16, | |
2280 | + 0x9045, 16, | |
2281 | + 0, 0, | |
2282 | + 0, 0, | |
2283 | + 0, 0, | |
2284 | + 0, 0, | |
2285 | + 0, 0, | |
2286 | + 0, 0, | |
2287 | + 0, 0, | |
2288 | + 0, 0, | |
2289 | + 0, 0, | |
2290 | + 0, 0, | |
2291 | + }; | |
2292 | + | |
2293 | + return copy_packages(code, pack, 2, space); | |
2294 | +} | |
2295 | + | |
2296 | +static int modet_to_package(struct go7007 *go, u16 *code, int space) | |
2297 | +{ | |
2298 | + int ret, mb, i, addr, cnt = 0; | |
2299 | + u16 pack[32]; | |
2300 | + u16 thresholds[] = { | |
2301 | + 0x200e, 0, | |
2302 | + 0xbf82, go->modet[0].pixel_threshold, | |
2303 | + 0xbf83, go->modet[1].pixel_threshold, | |
2304 | + 0xbf84, go->modet[2].pixel_threshold, | |
2305 | + 0xbf85, go->modet[3].pixel_threshold, | |
2306 | + 0xbf86, go->modet[0].motion_threshold, | |
2307 | + 0xbf87, go->modet[1].motion_threshold, | |
2308 | + 0xbf88, go->modet[2].motion_threshold, | |
2309 | + 0xbf89, go->modet[3].motion_threshold, | |
2310 | + 0xbf8a, go->modet[0].mb_threshold, | |
2311 | + 0xbf8b, go->modet[1].mb_threshold, | |
2312 | + 0xbf8c, go->modet[2].mb_threshold, | |
2313 | + 0xbf8d, go->modet[3].mb_threshold, | |
2314 | + 0xbf8e, 0, | |
2315 | + 0xbf8f, 0, | |
2316 | + 0, 0, | |
2317 | + }; | |
2318 | + | |
2319 | + ret = copy_packages(code, thresholds, 1, space); | |
2320 | + if (ret < 0) | |
2321 | + return -1; | |
2322 | + cnt += ret; | |
2323 | + | |
2324 | + addr = 0xbac0; | |
2325 | + memset(pack, 0, 64); | |
2326 | + i = 0; | |
2327 | + for (mb = 0; mb < 1624; ++mb) { | |
2328 | + pack[i * 2 + 3] <<= 2; | |
2329 | + pack[i * 2 + 3] |= go->modet_map[mb]; | |
2330 | + if (mb % 8 != 7) | |
2331 | + continue; | |
2332 | + pack[i * 2 + 2] = addr++; | |
2333 | + ++i; | |
2334 | + if (i == 10 || mb == 1623) { | |
2335 | + pack[0] = 0x2000 | i; | |
2336 | + ret = copy_packages(code + cnt, pack, 1, space - cnt); | |
2337 | + if (ret < 0) | |
2338 | + return -1; | |
2339 | + cnt += ret; | |
2340 | + i = 0; | |
2341 | + memset(pack, 0, 64); | |
2342 | + } | |
2343 | + pack[i * 2 + 3] = 0; | |
2344 | + } | |
2345 | + | |
2346 | + memset(pack, 0, 64); | |
2347 | + i = 0; | |
2348 | + for (addr = 0xbb90; addr < 0xbbfa; ++addr) { | |
2349 | + pack[i * 2 + 2] = addr; | |
2350 | + pack[i * 2 + 3] = 0; | |
2351 | + ++i; | |
2352 | + if (i == 10 || addr == 0xbbf9) { | |
2353 | + pack[0] = 0x2000 | i; | |
2354 | + ret = copy_packages(code + cnt, pack, 1, space - cnt); | |
2355 | + if (ret < 0) | |
2356 | + return -1; | |
2357 | + cnt += ret; | |
2358 | + i = 0; | |
2359 | + memset(pack, 0, 64); | |
2360 | + } | |
2361 | + } | |
2362 | + return cnt; | |
2363 | +} | |
2364 | + | |
2365 | +static int do_special(struct go7007 *go, u16 type, u16 *code, int space, | |
2366 | + int *framelen) | |
2367 | +{ | |
2368 | + switch (type) { | |
2369 | + case SPECIAL_FRM_HEAD: | |
2370 | + switch (go->format) { | |
2371 | + case GO7007_FORMAT_MJPEG: | |
2372 | + return gen_mjpeghdr_to_package(go, code, space); | |
2373 | + case GO7007_FORMAT_MPEG1: | |
2374 | + case GO7007_FORMAT_MPEG2: | |
2375 | + return gen_mpeg1hdr_to_package(go, code, space, | |
2376 | + framelen); | |
2377 | + case GO7007_FORMAT_MPEG4: | |
2378 | + return gen_mpeg4hdr_to_package(go, code, space, | |
2379 | + framelen); | |
2380 | + } | |
2381 | + case SPECIAL_BRC_CTRL: | |
2382 | + return brctrl_to_package(go, code, space, framelen); | |
2383 | + case SPECIAL_CONFIG: | |
2384 | + return config_package(go, code, space); | |
2385 | + case SPECIAL_SEQHEAD: | |
2386 | + switch (go->format) { | |
2387 | + case GO7007_FORMAT_MPEG1: | |
2388 | + case GO7007_FORMAT_MPEG2: | |
2389 | + return seqhead_to_package(go, code, space, | |
2390 | + mpeg1_sequence_header); | |
2391 | + case GO7007_FORMAT_MPEG4: | |
2392 | + return seqhead_to_package(go, code, space, | |
2393 | + mpeg4_sequence_header); | |
2394 | + default: | |
2395 | + return 0; | |
2396 | + } | |
2397 | + case SPECIAL_AV_SYNC: | |
2398 | + return avsync_to_package(go, code, space); | |
2399 | + case SPECIAL_FINAL: | |
2400 | + return final_package(go, code, space); | |
2401 | + case SPECIAL_AUDIO: | |
2402 | + return audio_to_package(go, code, space); | |
2403 | + case SPECIAL_MODET: | |
2404 | + return modet_to_package(go, code, space); | |
2405 | + } | |
2406 | + printk(KERN_ERR | |
2407 | + "go7007: firmware file contains unsupported feature %04x\n", | |
2408 | + type); | |
2409 | + return -1; | |
2410 | +} | |
2411 | + | |
2412 | +int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) | |
2413 | +{ | |
2414 | + const struct firmware *fw_entry; | |
2415 | + u16 *code, *src; | |
2416 | + int framelen[8] = { }; /* holds the lengths of empty frame templates */ | |
2417 | + int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags; | |
2418 | + int mode_flag; | |
2419 | + int ret; | |
2420 | + | |
2421 | + switch (go->format) { | |
2422 | + case GO7007_FORMAT_MJPEG: | |
2423 | + mode_flag = FLAG_MODE_MJPEG; | |
2424 | + break; | |
2425 | + case GO7007_FORMAT_MPEG1: | |
2426 | + mode_flag = FLAG_MODE_MPEG1; | |
2427 | + break; | |
2428 | + case GO7007_FORMAT_MPEG2: | |
2429 | + mode_flag = FLAG_MODE_MPEG2; | |
2430 | + break; | |
2431 | + case GO7007_FORMAT_MPEG4: | |
2432 | + mode_flag = FLAG_MODE_MPEG4; | |
2433 | + break; | |
2434 | + default: | |
2435 | + return -1; | |
2436 | + } | |
2437 | + if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) { | |
2438 | + printk(KERN_ERR | |
2439 | + "go7007: unable to load firmware from file \"%s\"\n", | |
2440 | + go->board_info->firmware); | |
2441 | + return -1; | |
2442 | + } | |
2443 | + code = kmalloc(codespace * 2, GFP_KERNEL); | |
2444 | + if (code == NULL) { | |
2445 | + printk(KERN_ERR "go7007: unable to allocate %d bytes for " | |
2446 | + "firmware construction\n", codespace * 2); | |
2447 | + goto fw_failed; | |
2448 | + } | |
2449 | + memset(code, 0, codespace * 2); | |
2450 | + src = (u16 *)fw_entry->data; | |
2451 | + srclen = fw_entry->size / 2; | |
2452 | + while (srclen >= 2) { | |
2453 | + chunk_flags = __le16_to_cpu(src[0]); | |
2454 | + chunk_len = __le16_to_cpu(src[1]); | |
2455 | + if (chunk_len + 2 > srclen) { | |
2456 | + printk(KERN_ERR "go7007: firmware file \"%s\" " | |
2457 | + "appears to be corrupted\n", | |
2458 | + go->board_info->firmware); | |
2459 | + goto fw_failed; | |
2460 | + } | |
2461 | + if (chunk_flags & mode_flag) { | |
2462 | + if (chunk_flags & FLAG_SPECIAL) { | |
2463 | + ret = do_special(go, __le16_to_cpu(src[2]), | |
2464 | + &code[i], codespace - i, framelen); | |
2465 | + if (ret < 0) { | |
2466 | + printk(KERN_ERR "go7007: insufficient " | |
2467 | + "memory for firmware " | |
2468 | + "construction\n"); | |
2469 | + goto fw_failed; | |
2470 | + } | |
2471 | + i += ret; | |
2472 | + } else { | |
2473 | + if (codespace - i < chunk_len) { | |
2474 | + printk(KERN_ERR "go7007: insufficient " | |
2475 | + "memory for firmware " | |
2476 | + "construction\n"); | |
2477 | + goto fw_failed; | |
2478 | + } | |
2479 | + memcpy(&code[i], &src[2], chunk_len * 2); | |
2480 | + i += chunk_len; | |
2481 | + } | |
2482 | + } | |
2483 | + srclen -= chunk_len + 2; | |
2484 | + src += chunk_len + 2; | |
2485 | + } | |
2486 | + release_firmware(fw_entry); | |
2487 | + *fw = (u8 *)code; | |
2488 | + *fwlen = i * 2; | |
2489 | + return 0; | |
2490 | + | |
2491 | +fw_failed: | |
2492 | + kfree(code); | |
2493 | + release_firmware(fw_entry); | |
2494 | + return -1; | |
2495 | +} | |
2496 | diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/go7007/go7007-i2c.c | |
2497 | new file mode 100644 | |
2498 | index 0000000..10baae3 | |
2499 | --- /dev/null | |
2500 | +++ b/drivers/staging/go7007/go7007-i2c.c | |
2501 | @@ -0,0 +1,309 @@ | |
2502 | +/* | |
2503 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
2504 | + * | |
2505 | + * This program is free software; you can redistribute it and/or modify | |
2506 | + * it under the terms of the GNU General Public License (Version 2) as | |
2507 | + * published by the Free Software Foundation. | |
2508 | + * | |
2509 | + * This program is distributed in the hope that it will be useful, | |
2510 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2511 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2512 | + * GNU General Public License for more details. | |
2513 | + * | |
2514 | + * You should have received a copy of the GNU General Public License | |
2515 | + * along with this program; if not, write to the Free Software Foundation, | |
2516 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
2517 | + */ | |
2518 | + | |
2519 | +#include <linux/version.h> | |
2520 | +#include <linux/module.h> | |
2521 | +#include <linux/init.h> | |
2522 | +#include <linux/delay.h> | |
2523 | +#include <linux/sched.h> | |
2524 | +#include <linux/list.h> | |
2525 | +#include <linux/unistd.h> | |
2526 | +#include <linux/time.h> | |
2527 | +#include <linux/device.h> | |
2528 | +#include <linux/i2c.h> | |
2529 | +#include <linux/semaphore.h> | |
2530 | +#include <linux/uaccess.h> | |
2531 | +#include <asm/system.h> | |
2532 | + | |
2533 | +#include "go7007-priv.h" | |
2534 | +#include "wis-i2c.h" | |
2535 | + | |
2536 | +/************** Registration interface for I2C client drivers **************/ | |
2537 | + | |
2538 | +/* Since there's no way to auto-probe the I2C devices connected to the I2C | |
2539 | + * bus on the go7007, we have this silly little registration system that | |
2540 | + * client drivers can use to register their I2C driver ID and their | |
2541 | + * detect_client function (the one that's normally passed to i2c_probe). | |
2542 | + * | |
2543 | + * When a new go7007 device is connected, we can look up in a board info | |
2544 | + * table by the USB or PCI vendor/product/revision ID to determine | |
2545 | + * which I2C client module to load. The client driver module will register | |
2546 | + * itself here, and then we can call the registered detect_client function | |
2547 | + * to force-load a new client at the address listed in the board info table. | |
2548 | + * | |
2549 | + * Really the I2C subsystem should have a way to force-load I2C client | |
2550 | + * drivers when we have a priori knowledge of what's on the bus, especially | |
2551 | + * since the existing I2C auto-probe mechanism is so hokey, but we'll use | |
2552 | + * our own mechanism for the time being. */ | |
2553 | + | |
2554 | +struct wis_i2c_client_driver { | |
2555 | + unsigned int id; | |
2556 | + found_proc found_proc; | |
2557 | + struct list_head list; | |
2558 | +}; | |
2559 | + | |
2560 | +static LIST_HEAD(i2c_client_drivers); | |
2561 | +static DECLARE_MUTEX(i2c_client_driver_list_lock); | |
2562 | + | |
2563 | +/* Client drivers register here by their I2C driver ID */ | |
2564 | +int wis_i2c_add_driver(unsigned int id, found_proc found_proc) | |
2565 | +{ | |
2566 | + struct wis_i2c_client_driver *driver; | |
2567 | + | |
2568 | + driver = kmalloc(sizeof(struct wis_i2c_client_driver), GFP_KERNEL); | |
2569 | + if (driver == NULL) | |
2570 | + return -ENOMEM; | |
2571 | + driver->id = id; | |
2572 | + driver->found_proc = found_proc; | |
2573 | + | |
2574 | + down(&i2c_client_driver_list_lock); | |
2575 | + list_add_tail(&driver->list, &i2c_client_drivers); | |
2576 | + up(&i2c_client_driver_list_lock); | |
2577 | + | |
2578 | + return 0; | |
2579 | +} | |
2580 | +EXPORT_SYMBOL(wis_i2c_add_driver); | |
2581 | + | |
2582 | +void wis_i2c_del_driver(found_proc found_proc) | |
2583 | +{ | |
2584 | + struct wis_i2c_client_driver *driver, *next; | |
2585 | + | |
2586 | + down(&i2c_client_driver_list_lock); | |
2587 | + list_for_each_entry_safe(driver, next, &i2c_client_drivers, list) | |
2588 | + if (driver->found_proc == found_proc) { | |
2589 | + list_del(&driver->list); | |
2590 | + kfree(driver); | |
2591 | + } | |
2592 | + up(&i2c_client_driver_list_lock); | |
2593 | +} | |
2594 | +EXPORT_SYMBOL(wis_i2c_del_driver); | |
2595 | + | |
2596 | +/* The main go7007 driver calls this to instantiate a client by driver | |
2597 | + * ID and bus address, which are both stored in the board info table */ | |
2598 | +int wis_i2c_probe_device(struct i2c_adapter *adapter, | |
2599 | + unsigned int id, int addr) | |
2600 | +{ | |
2601 | + struct wis_i2c_client_driver *driver; | |
2602 | + int found = 0; | |
2603 | + | |
2604 | + if (addr < 0 || addr > 0x7f) | |
2605 | + return -1; | |
2606 | + down(&i2c_client_driver_list_lock); | |
2607 | + list_for_each_entry(driver, &i2c_client_drivers, list) | |
2608 | + if (driver->id == id) { | |
2609 | + if (driver->found_proc(adapter, addr, 0) == 0) | |
2610 | + found = 1; | |
2611 | + break; | |
2612 | + } | |
2613 | + up(&i2c_client_driver_list_lock); | |
2614 | + return found; | |
2615 | +} | |
2616 | + | |
2617 | +/********************* Driver for on-board I2C adapter *********************/ | |
2618 | + | |
2619 | +/* #define GO7007_I2C_DEBUG */ | |
2620 | + | |
2621 | +#define SPI_I2C_ADDR_BASE 0x1400 | |
2622 | +#define STATUS_REG_ADDR (SPI_I2C_ADDR_BASE + 0x2) | |
2623 | +#define I2C_CTRL_REG_ADDR (SPI_I2C_ADDR_BASE + 0x6) | |
2624 | +#define I2C_DEV_UP_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x7) | |
2625 | +#define I2C_LO_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x8) | |
2626 | +#define I2C_DATA_REG_ADDR (SPI_I2C_ADDR_BASE + 0x9) | |
2627 | +#define I2C_CLKFREQ_REG_ADDR (SPI_I2C_ADDR_BASE + 0xa) | |
2628 | + | |
2629 | +#define I2C_STATE_MASK 0x0007 | |
2630 | +#define I2C_READ_READY_MASK 0x0008 | |
2631 | + | |
2632 | +/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs | |
2633 | + * on the Adlink PCI-MPG24, so access is shared between all of them. */ | |
2634 | +static DECLARE_MUTEX(adlink_mpg24_i2c_lock); | |
2635 | + | |
2636 | +static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, | |
2637 | + u16 command, int flags, u8 *data) | |
2638 | +{ | |
2639 | + int i, ret = -1; | |
2640 | + u16 val; | |
2641 | + | |
2642 | + if (go->status == STATUS_SHUTDOWN) | |
2643 | + return -1; | |
2644 | + | |
2645 | +#ifdef GO7007_I2C_DEBUG | |
2646 | + if (read) | |
2647 | + printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n", | |
2648 | + command, addr); | |
2649 | + else | |
2650 | + printk(KERN_DEBUG | |
2651 | + "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n", | |
2652 | + *data, command, addr); | |
2653 | +#endif | |
2654 | + | |
2655 | + down(&go->hw_lock); | |
2656 | + | |
2657 | + if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { | |
2658 | + /* Bridge the I2C port on this GO7007 to the shared bus */ | |
2659 | + down(&adlink_mpg24_i2c_lock); | |
2660 | + go7007_write_addr(go, 0x3c82, 0x0020); | |
2661 | + } | |
2662 | + | |
2663 | + /* Wait for I2C adapter to be ready */ | |
2664 | + for (i = 0; i < 10; ++i) { | |
2665 | + if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) | |
2666 | + goto i2c_done; | |
2667 | + if (!(val & I2C_STATE_MASK)) | |
2668 | + break; | |
2669 | + msleep(100); | |
2670 | + } | |
2671 | + if (i == 10) { | |
2672 | + printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); | |
2673 | + goto i2c_done; | |
2674 | + } | |
2675 | + | |
2676 | + /* Set target register (command) */ | |
2677 | + go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags); | |
2678 | + go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command); | |
2679 | + | |
2680 | + /* If we're writing, send the data and target address and we're done */ | |
2681 | + if (!read) { | |
2682 | + go7007_write_addr(go, I2C_DATA_REG_ADDR, *data); | |
2683 | + go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, | |
2684 | + (addr << 9) | (command >> 8)); | |
2685 | + ret = 0; | |
2686 | + goto i2c_done; | |
2687 | + } | |
2688 | + | |
2689 | + /* Otherwise, we're reading. First clear i2c_rx_data_rdy. */ | |
2690 | + if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) | |
2691 | + goto i2c_done; | |
2692 | + | |
2693 | + /* Send the target address plus read flag */ | |
2694 | + go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, | |
2695 | + (addr << 9) | 0x0100 | (command >> 8)); | |
2696 | + | |
2697 | + /* Wait for i2c_rx_data_rdy */ | |
2698 | + for (i = 0; i < 10; ++i) { | |
2699 | + if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) | |
2700 | + goto i2c_done; | |
2701 | + if (val & I2C_READ_READY_MASK) | |
2702 | + break; | |
2703 | + msleep(100); | |
2704 | + } | |
2705 | + if (i == 10) { | |
2706 | + printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); | |
2707 | + goto i2c_done; | |
2708 | + } | |
2709 | + | |
2710 | + /* Retrieve the read byte */ | |
2711 | + if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) | |
2712 | + goto i2c_done; | |
2713 | + *data = val; | |
2714 | + ret = 0; | |
2715 | + | |
2716 | +i2c_done: | |
2717 | + if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { | |
2718 | + /* Isolate the I2C port on this GO7007 from the shared bus */ | |
2719 | + go7007_write_addr(go, 0x3c82, 0x0000); | |
2720 | + up(&adlink_mpg24_i2c_lock); | |
2721 | + } | |
2722 | + up(&go->hw_lock); | |
2723 | + return ret; | |
2724 | +} | |
2725 | + | |
2726 | +static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | |
2727 | + unsigned short flags, char read_write, | |
2728 | + u8 command, int size, union i2c_smbus_data *data) | |
2729 | +{ | |
2730 | + struct go7007 *go = i2c_get_adapdata(adapter); | |
2731 | + | |
2732 | + if (size != I2C_SMBUS_BYTE_DATA) | |
2733 | + return -1; | |
2734 | + return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command, | |
2735 | + flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte); | |
2736 | +} | |
2737 | + | |
2738 | +/* VERY LIMITED I2C master xfer function -- only needed because the | |
2739 | + * SMBus functions only support 8-bit commands and the SAA7135 uses | |
2740 | + * 16-bit commands. The I2C interface on the GO7007, as limited as | |
2741 | + * it is, does support this mode. */ | |
2742 | + | |
2743 | +static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, | |
2744 | + struct i2c_msg msgs[], int num) | |
2745 | +{ | |
2746 | + struct go7007 *go = i2c_get_adapdata(adapter); | |
2747 | + int i; | |
2748 | + | |
2749 | + for (i = 0; i < num; ++i) { | |
2750 | + /* We can only do two things here -- write three bytes, or | |
2751 | + * write two bytes and read one byte. */ | |
2752 | + if (msgs[i].len == 2) { | |
2753 | + if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr || | |
2754 | + (msgs[i].flags & I2C_M_RD) || | |
2755 | + !(msgs[i + 1].flags & I2C_M_RD) || | |
2756 | + msgs[i + 1].len != 1) | |
2757 | + return -1; | |
2758 | + if (go7007_i2c_xfer(go, msgs[i].addr, 1, | |
2759 | + (msgs[i].buf[0] << 8) | msgs[i].buf[1], | |
2760 | + 0x01, &msgs[i + 1].buf[0]) < 0) | |
2761 | + return -1; | |
2762 | + ++i; | |
2763 | + } else if (msgs[i].len == 3) { | |
2764 | + if (msgs[i].flags & I2C_M_RD) | |
2765 | + return -1; | |
2766 | + if (msgs[i].len != 3) | |
2767 | + return -1; | |
2768 | + if (go7007_i2c_xfer(go, msgs[i].addr, 0, | |
2769 | + (msgs[i].buf[0] << 8) | msgs[i].buf[1], | |
2770 | + 0x01, &msgs[i].buf[2]) < 0) | |
2771 | + return -1; | |
2772 | + } else | |
2773 | + return -1; | |
2774 | + } | |
2775 | + | |
2776 | + return 0; | |
2777 | +} | |
2778 | + | |
2779 | +static u32 go7007_functionality(struct i2c_adapter *adapter) | |
2780 | +{ | |
2781 | + return I2C_FUNC_SMBUS_BYTE_DATA; | |
2782 | +} | |
2783 | + | |
2784 | +static struct i2c_algorithm go7007_algo = { | |
2785 | + .smbus_xfer = go7007_smbus_xfer, | |
2786 | + .master_xfer = go7007_i2c_master_xfer, | |
2787 | + .functionality = go7007_functionality, | |
2788 | +}; | |
2789 | + | |
2790 | +static struct i2c_adapter go7007_adap_templ = { | |
2791 | + .owner = THIS_MODULE, | |
2792 | + .class = I2C_CLASS_TV_ANALOG, | |
2793 | + .name = "WIS GO7007SB", | |
2794 | + .id = I2C_ALGO_GO7007, | |
2795 | + .algo = &go7007_algo, | |
2796 | +}; | |
2797 | + | |
2798 | +int go7007_i2c_init(struct go7007 *go) | |
2799 | +{ | |
2800 | + memcpy(&go->i2c_adapter, &go7007_adap_templ, | |
2801 | + sizeof(go7007_adap_templ)); | |
2802 | + go->i2c_adapter.dev.parent = go->dev; | |
2803 | + i2c_set_adapdata(&go->i2c_adapter, go); | |
2804 | + if (i2c_add_adapter(&go->i2c_adapter) < 0) { | |
2805 | + printk(KERN_ERR | |
2806 | + "go7007-i2c: error: i2c_add_adapter failed\n"); | |
2807 | + return -1; | |
2808 | + } | |
2809 | + return 0; | |
2810 | +} | |
2811 | diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/go7007/go7007-priv.h | |
2812 | new file mode 100644 | |
2813 | index 0000000..005542d | |
2814 | --- /dev/null | |
2815 | +++ b/drivers/staging/go7007/go7007-priv.h | |
2816 | @@ -0,0 +1,279 @@ | |
2817 | +/* | |
2818 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
2819 | + * | |
2820 | + * This program is free software; you can redistribute it and/or modify | |
2821 | + * it under the terms of the GNU General Public License (Version 2) as | |
2822 | + * published by the Free Software Foundation. | |
2823 | + * | |
2824 | + * This program is distributed in the hope that it will be useful, | |
2825 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2826 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2827 | + * GNU General Public License for more details. | |
2828 | + * | |
2829 | + * You should have received a copy of the GNU General Public License | |
2830 | + * along with this program; if not, write to the Free Software Foundation, | |
2831 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
2832 | + */ | |
2833 | + | |
2834 | +/* | |
2835 | + * This is the private include file for the go7007 driver. It should not | |
2836 | + * be included by anybody but the driver itself, and especially not by | |
2837 | + * user-space applications. | |
2838 | + */ | |
2839 | + | |
2840 | +struct go7007; | |
2841 | + | |
2842 | +/* IDs to activate board-specific support code */ | |
2843 | +#define GO7007_BOARDID_MATRIX_II 0 | |
2844 | +#define GO7007_BOARDID_MATRIX_RELOAD 1 | |
2845 | +#define GO7007_BOARDID_STAR_TREK 2 | |
2846 | +#define GO7007_BOARDID_PCI_VOYAGER 3 | |
2847 | +#define GO7007_BOARDID_XMEN 4 | |
2848 | +#define GO7007_BOARDID_XMEN_II 5 | |
2849 | +#define GO7007_BOARDID_XMEN_III 6 | |
2850 | +#define GO7007_BOARDID_MATRIX_REV 7 | |
2851 | +#define GO7007_BOARDID_PX_M402U 16 | |
2852 | +#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */ | |
2853 | +#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */ | |
2854 | +#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */ | |
2855 | +#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */ | |
2856 | +#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */ | |
2857 | +#define GO7007_BOARDID_ENDURA 22 | |
2858 | +#define GO7007_BOARDID_ADLINK_MPG24 23 | |
2859 | + | |
2860 | +/* Various characteristics of each board */ | |
2861 | +#define GO7007_BOARD_HAS_AUDIO (1<<0) | |
2862 | +#define GO7007_BOARD_USE_ONBOARD_I2C (1<<1) | |
2863 | +#define GO7007_BOARD_HAS_TUNER (1<<2) | |
2864 | + | |
2865 | +/* Characteristics of sensor devices */ | |
2866 | +#define GO7007_SENSOR_VALID_POLAR (1<<0) | |
2867 | +#define GO7007_SENSOR_HREF_POLAR (1<<1) | |
2868 | +#define GO7007_SENSOR_VREF_POLAR (1<<2) | |
2869 | +#define GO7007_SENSOR_FIELD_ID_POLAR (1<<3) | |
2870 | +#define GO7007_SENSOR_BIT_WIDTH (1<<4) | |
2871 | +#define GO7007_SENSOR_VALID_ENABLE (1<<5) | |
2872 | +#define GO7007_SENSOR_656 (1<<6) | |
2873 | +#define GO7007_SENSOR_CONFIG_MASK 0x7f | |
2874 | +#define GO7007_SENSOR_TV (1<<7) | |
2875 | +#define GO7007_SENSOR_VBI (1<<8) | |
2876 | +#define GO7007_SENSOR_SCALING (1<<9) | |
2877 | + | |
2878 | +/* Characteristics of audio sensor devices */ | |
2879 | +#define GO7007_AUDIO_I2S_MODE_1 (1) | |
2880 | +#define GO7007_AUDIO_I2S_MODE_2 (2) | |
2881 | +#define GO7007_AUDIO_I2S_MODE_3 (3) | |
2882 | +#define GO7007_AUDIO_BCLK_POLAR (1<<2) | |
2883 | +#define GO7007_AUDIO_WORD_14 (14<<4) | |
2884 | +#define GO7007_AUDIO_WORD_16 (16<<4) | |
2885 | +#define GO7007_AUDIO_ONE_CHANNEL (1<<11) | |
2886 | +#define GO7007_AUDIO_I2S_MASTER (1<<16) | |
2887 | +#define GO7007_AUDIO_OKI_MODE (1<<17) | |
2888 | + | |
2889 | +struct go7007_board_info { | |
2890 | + char *firmware; | |
2891 | + unsigned int flags; | |
2892 | + int hpi_buffer_cap; | |
2893 | + unsigned int sensor_flags; | |
2894 | + int sensor_width; | |
2895 | + int sensor_height; | |
2896 | + int sensor_framerate; | |
2897 | + int sensor_h_offset; | |
2898 | + int sensor_v_offset; | |
2899 | + unsigned int audio_flags; | |
2900 | + int audio_rate; | |
2901 | + int audio_bclk_div; | |
2902 | + int audio_main_div; | |
2903 | + int num_i2c_devs; | |
2904 | + struct { | |
2905 | + int id; | |
2906 | + int addr; | |
2907 | + } i2c_devs[4]; | |
2908 | + int num_inputs; | |
2909 | + struct { | |
2910 | + int video_input; | |
2911 | + int audio_input; | |
2912 | + char *name; | |
2913 | + } inputs[4]; | |
2914 | +}; | |
2915 | + | |
2916 | +struct go7007_hpi_ops { | |
2917 | + int (*interface_reset)(struct go7007 *go); | |
2918 | + int (*write_interrupt)(struct go7007 *go, int addr, int data); | |
2919 | + int (*read_interrupt)(struct go7007 *go); | |
2920 | + int (*stream_start)(struct go7007 *go); | |
2921 | + int (*stream_stop)(struct go7007 *go); | |
2922 | + int (*send_firmware)(struct go7007 *go, u8 *data, int len); | |
2923 | +}; | |
2924 | + | |
2925 | +/* The video buffer size must be a multiple of PAGE_SIZE */ | |
2926 | +#define GO7007_BUF_PAGES (128 * 1024 / PAGE_SIZE) | |
2927 | +#define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT) | |
2928 | + | |
2929 | +struct go7007_buffer { | |
2930 | + struct go7007 *go; /* Reverse reference for VMA ops */ | |
2931 | + int index; /* Reverse reference for DQBUF */ | |
2932 | + enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state; | |
2933 | + u32 seq; | |
2934 | + struct timeval timestamp; | |
2935 | + struct list_head stream; | |
2936 | + struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */ | |
2937 | + unsigned long user_addr; | |
2938 | + unsigned int page_count; | |
2939 | + unsigned int offset; | |
2940 | + unsigned int bytesused; | |
2941 | + unsigned int frame_offset; | |
2942 | + u32 modet_active; | |
2943 | + int mapped; | |
2944 | +}; | |
2945 | + | |
2946 | +struct go7007_file { | |
2947 | + struct go7007 *go; | |
2948 | + struct semaphore lock; | |
2949 | + int buf_count; | |
2950 | + struct go7007_buffer *bufs; | |
2951 | +}; | |
2952 | + | |
2953 | +#define GO7007_FORMAT_MJPEG 0 | |
2954 | +#define GO7007_FORMAT_MPEG4 1 | |
2955 | +#define GO7007_FORMAT_MPEG1 2 | |
2956 | +#define GO7007_FORMAT_MPEG2 3 | |
2957 | +#define GO7007_FORMAT_H263 4 | |
2958 | + | |
2959 | +#define GO7007_RATIO_1_1 0 | |
2960 | +#define GO7007_RATIO_4_3 1 | |
2961 | +#define GO7007_RATIO_16_9 2 | |
2962 | + | |
2963 | +enum go7007_parser_state { | |
2964 | + STATE_DATA, | |
2965 | + STATE_00, | |
2966 | + STATE_00_00, | |
2967 | + STATE_00_00_01, | |
2968 | + STATE_FF, | |
2969 | + STATE_VBI_LEN_A, | |
2970 | + STATE_VBI_LEN_B, | |
2971 | + STATE_MODET_MAP, | |
2972 | + STATE_UNPARSED, | |
2973 | +}; | |
2974 | + | |
2975 | +struct go7007 { | |
2976 | + struct device *dev; | |
2977 | + struct go7007_board_info *board_info; | |
2978 | + unsigned int board_id; | |
2979 | + int tuner_type; | |
2980 | + int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ | |
2981 | + char name[64]; | |
2982 | + struct video_device *video_dev; | |
2983 | + int ref_count; | |
2984 | + enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; | |
2985 | + spinlock_t spinlock; | |
2986 | + struct semaphore hw_lock; | |
2987 | + int streaming; | |
2988 | + int in_use; | |
2989 | + int audio_enabled; | |
2990 | + | |
2991 | + /* Video input */ | |
2992 | + int input; | |
2993 | + enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard; | |
2994 | + int sensor_framerate; | |
2995 | + int width; | |
2996 | + int height; | |
2997 | + int encoder_h_offset; | |
2998 | + int encoder_v_offset; | |
2999 | + unsigned int encoder_h_halve:1; | |
3000 | + unsigned int encoder_v_halve:1; | |
3001 | + unsigned int encoder_subsample:1; | |
3002 | + | |
3003 | + /* Encoder config */ | |
3004 | + int format; | |
3005 | + int bitrate; | |
3006 | + int fps_scale; | |
3007 | + int pali; | |
3008 | + int aspect_ratio; | |
3009 | + int gop_size; | |
3010 | + unsigned int ipb:1; | |
3011 | + unsigned int closed_gop:1; | |
3012 | + unsigned int repeat_seqhead:1; | |
3013 | + unsigned int seq_header_enable:1; | |
3014 | + unsigned int gop_header_enable:1; | |
3015 | + unsigned int dvd_mode:1; | |
3016 | + unsigned int interlace_coding:1; | |
3017 | + | |
3018 | + /* Motion detection */ | |
3019 | + unsigned int modet_enable:1; | |
3020 | + struct { | |
3021 | + unsigned int enable:1; | |
3022 | + int pixel_threshold; | |
3023 | + int motion_threshold; | |
3024 | + int mb_threshold; | |
3025 | + } modet[4]; | |
3026 | + unsigned char modet_map[1624]; | |
3027 | + unsigned char active_map[216]; | |
3028 | + | |
3029 | + /* Video streaming */ | |
3030 | + struct go7007_buffer *active_buf; | |
3031 | + enum go7007_parser_state state; | |
3032 | + int parse_length; | |
3033 | + u16 modet_word; | |
3034 | + int seen_frame; | |
3035 | + u32 next_seq; | |
3036 | + struct list_head stream; | |
3037 | + wait_queue_head_t frame_waitq; | |
3038 | + | |
3039 | + /* Audio streaming */ | |
3040 | + void (*audio_deliver)(struct go7007 *go, u8 *buf, int length); | |
3041 | + void *snd_context; | |
3042 | + | |
3043 | + /* I2C */ | |
3044 | + int i2c_adapter_online; | |
3045 | + struct i2c_adapter i2c_adapter; | |
3046 | + | |
3047 | + /* HPI driver */ | |
3048 | + struct go7007_hpi_ops *hpi_ops; | |
3049 | + void *hpi_context; | |
3050 | + int interrupt_available; | |
3051 | + wait_queue_head_t interrupt_waitq; | |
3052 | + unsigned short interrupt_value; | |
3053 | + unsigned short interrupt_data; | |
3054 | +}; | |
3055 | + | |
3056 | +/* All of these must be called with the hpi_lock semaphore held! */ | |
3057 | +#define go7007_interface_reset(go) \ | |
3058 | + ((go)->hpi_ops->interface_reset(go)) | |
3059 | +#define go7007_write_interrupt(go, x, y) \ | |
3060 | + ((go)->hpi_ops->write_interrupt)((go), (x), (y)) | |
3061 | +#define go7007_stream_start(go) \ | |
3062 | + ((go)->hpi_ops->stream_start(go)) | |
3063 | +#define go7007_stream_stop(go) \ | |
3064 | + ((go)->hpi_ops->stream_stop(go)) | |
3065 | +#define go7007_send_firmware(go, x, y) \ | |
3066 | + ((go)->hpi_ops->send_firmware)((go), (x), (y)) | |
3067 | +#define go7007_write_addr(go, x, y) \ | |
3068 | + ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y)) | |
3069 | + | |
3070 | +/* go7007-driver.c */ | |
3071 | +int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data); | |
3072 | +int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data); | |
3073 | +int go7007_boot_encoder(struct go7007 *go, int init_i2c); | |
3074 | +int go7007_reset_encoder(struct go7007 *go); | |
3075 | +int go7007_register_encoder(struct go7007 *go); | |
3076 | +int go7007_start_encoder(struct go7007 *go); | |
3077 | +void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); | |
3078 | +struct go7007 *go7007_alloc(struct go7007_board_info *board, | |
3079 | + struct device *dev); | |
3080 | +void go7007_remove(struct go7007 *go); | |
3081 | + | |
3082 | +/* go7007-fw.c */ | |
3083 | +int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen); | |
3084 | + | |
3085 | +/* go7007-i2c.c */ | |
3086 | +int go7007_i2c_init(struct go7007 *go); | |
3087 | +int go7007_i2c_remove(struct go7007 *go); | |
3088 | + | |
3089 | +/* go7007-v4l2.c */ | |
3090 | +int go7007_v4l2_init(struct go7007 *go); | |
3091 | +void go7007_v4l2_remove(struct go7007 *go); | |
3092 | + | |
3093 | +/* snd-go7007.c */ | |
3094 | +int go7007_snd_init(struct go7007 *go); | |
3095 | +int go7007_snd_remove(struct go7007 *go); | |
3096 | diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c | |
3097 | new file mode 100644 | |
3098 | index 0000000..d4ed6d2 | |
3099 | --- /dev/null | |
3100 | +++ b/drivers/staging/go7007/go7007-usb.c | |
3101 | @@ -0,0 +1,1229 @@ | |
3102 | +/* | |
3103 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
3104 | + * | |
3105 | + * This program is free software; you can redistribute it and/or modify | |
3106 | + * it under the terms of the GNU General Public License (Version 2) as | |
3107 | + * published by the Free Software Foundation. | |
3108 | + * | |
3109 | + * This program is distributed in the hope that it will be useful, | |
3110 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
3111 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
3112 | + * GNU General Public License for more details. | |
3113 | + * | |
3114 | + * You should have received a copy of the GNU General Public License | |
3115 | + * along with this program; if not, write to the Free Software Foundation, | |
3116 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
3117 | + */ | |
3118 | + | |
3119 | +#include <linux/module.h> | |
3120 | +#include <linux/version.h> | |
3121 | +#include <linux/kernel.h> | |
3122 | +#include <linux/init.h> | |
3123 | +#include <linux/wait.h> | |
3124 | +#include <linux/list.h> | |
3125 | +#include <linux/slab.h> | |
3126 | +#include <linux/time.h> | |
3127 | +#include <linux/mm.h> | |
3128 | +#include <linux/usb.h> | |
3129 | +#include <linux/i2c.h> | |
3130 | +#include <asm/byteorder.h> | |
3131 | +#include <media/tvaudio.h> | |
3132 | + | |
3133 | +#include "go7007-priv.h" | |
3134 | +#include "wis-i2c.h" | |
3135 | + | |
3136 | +static unsigned int assume_endura; | |
3137 | +module_param(assume_endura, int, 0644); | |
3138 | +MODULE_PARM_DESC(assume_endura, "when probing fails, hardware is a Pelco Endura"); | |
3139 | + | |
3140 | +/* #define GO7007_USB_DEBUG */ | |
3141 | +/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */ | |
3142 | + | |
3143 | +#define HPI_STATUS_ADDR 0xFFF4 | |
3144 | +#define INT_PARAM_ADDR 0xFFF6 | |
3145 | +#define INT_INDEX_ADDR 0xFFF8 | |
3146 | + | |
3147 | +/* | |
3148 | + * Pipes on EZ-USB interface: | |
3149 | + * 0 snd - Control | |
3150 | + * 0 rcv - Control | |
3151 | + * 2 snd - Download firmware (control) | |
3152 | + * 4 rcv - Read Interrupt (interrupt) | |
3153 | + * 6 rcv - Read Video (bulk) | |
3154 | + * 8 rcv - Read Audio (bulk) | |
3155 | + */ | |
3156 | + | |
3157 | +#define GO7007_USB_EZUSB (1<<0) | |
3158 | +#define GO7007_USB_EZUSB_I2C (1<<1) | |
3159 | + | |
3160 | +struct go7007_usb_board { | |
3161 | + unsigned int flags; | |
3162 | + struct go7007_board_info main_info; | |
3163 | +}; | |
3164 | + | |
3165 | +struct go7007_usb { | |
3166 | + struct go7007_usb_board *board; | |
3167 | + struct semaphore i2c_lock; | |
3168 | + struct usb_device *usbdev; | |
3169 | + struct urb *video_urbs[8]; | |
3170 | + struct urb *audio_urbs[8]; | |
3171 | + struct urb *intr_urb; | |
3172 | +}; | |
3173 | + | |
3174 | +/*********************** Product specification data ***********************/ | |
3175 | + | |
3176 | +static struct go7007_usb_board board_matrix_ii = { | |
3177 | + .flags = GO7007_USB_EZUSB, | |
3178 | + .main_info = { | |
3179 | + .firmware = "go7007tv.bin", | |
3180 | + .flags = GO7007_BOARD_HAS_AUDIO | | |
3181 | + GO7007_BOARD_USE_ONBOARD_I2C, | |
3182 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3183 | + GO7007_AUDIO_WORD_16, | |
3184 | + .audio_rate = 48000, | |
3185 | + .audio_bclk_div = 8, | |
3186 | + .audio_main_div = 2, | |
3187 | + .hpi_buffer_cap = 7, | |
3188 | + .sensor_flags = GO7007_SENSOR_656 | | |
3189 | + GO7007_SENSOR_VALID_ENABLE | | |
3190 | + GO7007_SENSOR_TV | | |
3191 | + GO7007_SENSOR_VBI | | |
3192 | + GO7007_SENSOR_SCALING, | |
3193 | + .num_i2c_devs = 1, | |
3194 | + .i2c_devs = { | |
3195 | + { | |
3196 | + .id = I2C_DRIVERID_WIS_SAA7115, | |
3197 | + .addr = 0x20, | |
3198 | + }, | |
3199 | + }, | |
3200 | + .num_inputs = 2, | |
3201 | + .inputs = { | |
3202 | + { | |
3203 | + .video_input = 0, | |
3204 | + .name = "Composite", | |
3205 | + }, | |
3206 | + { | |
3207 | + .video_input = 9, | |
3208 | + .name = "S-Video", | |
3209 | + }, | |
3210 | + }, | |
3211 | + }, | |
3212 | +}; | |
3213 | + | |
3214 | +static struct go7007_usb_board board_matrix_reload = { | |
3215 | + .flags = GO7007_USB_EZUSB, | |
3216 | + .main_info = { | |
3217 | + .firmware = "go7007tv.bin", | |
3218 | + .flags = GO7007_BOARD_HAS_AUDIO | | |
3219 | + GO7007_BOARD_USE_ONBOARD_I2C, | |
3220 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3221 | + GO7007_AUDIO_I2S_MASTER | | |
3222 | + GO7007_AUDIO_WORD_16, | |
3223 | + .audio_rate = 48000, | |
3224 | + .audio_bclk_div = 8, | |
3225 | + .audio_main_div = 2, | |
3226 | + .hpi_buffer_cap = 7, | |
3227 | + .sensor_flags = GO7007_SENSOR_656 | | |
3228 | + GO7007_SENSOR_TV, | |
3229 | + .num_i2c_devs = 1, | |
3230 | + .i2c_devs = { | |
3231 | + { | |
3232 | + .id = I2C_DRIVERID_WIS_SAA7113, | |
3233 | + .addr = 0x25, | |
3234 | + }, | |
3235 | + }, | |
3236 | + .num_inputs = 2, | |
3237 | + .inputs = { | |
3238 | + { | |
3239 | + .video_input = 0, | |
3240 | + .name = "Composite", | |
3241 | + }, | |
3242 | + { | |
3243 | + .video_input = 9, | |
3244 | + .name = "S-Video", | |
3245 | + }, | |
3246 | + }, | |
3247 | + }, | |
3248 | +}; | |
3249 | + | |
3250 | +static struct go7007_usb_board board_star_trek = { | |
3251 | + .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, | |
3252 | + .main_info = { | |
3253 | + .firmware = "go7007tv.bin", | |
3254 | + .flags = GO7007_BOARD_HAS_AUDIO, /* | | |
3255 | + GO7007_BOARD_HAS_TUNER, */ | |
3256 | + .sensor_flags = GO7007_SENSOR_656 | | |
3257 | + GO7007_SENSOR_VALID_ENABLE | | |
3258 | + GO7007_SENSOR_TV | | |
3259 | + GO7007_SENSOR_VBI | | |
3260 | + GO7007_SENSOR_SCALING, | |
3261 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3262 | + GO7007_AUDIO_WORD_16, | |
3263 | + .audio_bclk_div = 8, | |
3264 | + .audio_main_div = 2, | |
3265 | + .hpi_buffer_cap = 7, | |
3266 | + .num_i2c_devs = 1, | |
3267 | + .i2c_devs = { | |
3268 | + { | |
3269 | + .id = I2C_DRIVERID_WIS_SAA7115, | |
3270 | + .addr = 0x20, | |
3271 | + }, | |
3272 | + }, | |
3273 | + .num_inputs = 2, | |
3274 | + .inputs = { | |
3275 | + { | |
3276 | + .video_input = 1, | |
3277 | + /* .audio_input = AUDIO_EXTERN, */ | |
3278 | + .name = "Composite", | |
3279 | + }, | |
3280 | + { | |
3281 | + .video_input = 8, | |
3282 | + /* .audio_input = AUDIO_EXTERN, */ | |
3283 | + .name = "S-Video", | |
3284 | + }, | |
3285 | + /* { | |
3286 | + * .video_input = 3, | |
3287 | + * .audio_input = AUDIO_TUNER, | |
3288 | + * .name = "Tuner", | |
3289 | + * }, | |
3290 | + */ | |
3291 | + }, | |
3292 | + }, | |
3293 | +}; | |
3294 | + | |
3295 | +static struct go7007_usb_board board_px_tv402u = { | |
3296 | + .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, | |
3297 | + .main_info = { | |
3298 | + .firmware = "go7007tv.bin", | |
3299 | + .flags = GO7007_BOARD_HAS_AUDIO | | |
3300 | + GO7007_BOARD_HAS_TUNER, | |
3301 | + .sensor_flags = GO7007_SENSOR_656 | | |
3302 | + GO7007_SENSOR_VALID_ENABLE | | |
3303 | + GO7007_SENSOR_TV | | |
3304 | + GO7007_SENSOR_VBI | | |
3305 | + GO7007_SENSOR_SCALING, | |
3306 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3307 | + GO7007_AUDIO_WORD_16, | |
3308 | + .audio_bclk_div = 8, | |
3309 | + .audio_main_div = 2, | |
3310 | + .hpi_buffer_cap = 7, | |
3311 | + .num_i2c_devs = 3, | |
3312 | + .i2c_devs = { | |
3313 | + { | |
3314 | + .id = I2C_DRIVERID_WIS_SAA7115, | |
3315 | + .addr = 0x20, | |
3316 | + }, | |
3317 | + { | |
3318 | + .id = I2C_DRIVERID_WIS_UDA1342, | |
3319 | + .addr = 0x1a, | |
3320 | + }, | |
3321 | + { | |
3322 | + .id = I2C_DRIVERID_WIS_SONY_TUNER, | |
3323 | + .addr = 0x60, | |
3324 | + }, | |
3325 | + }, | |
3326 | + .num_inputs = 3, | |
3327 | + .inputs = { | |
3328 | + { | |
3329 | + .video_input = 1, | |
3330 | + .audio_input = TVAUDIO_INPUT_EXTERN, | |
3331 | + .name = "Composite", | |
3332 | + }, | |
3333 | + { | |
3334 | + .video_input = 8, | |
3335 | + .audio_input = TVAUDIO_INPUT_EXTERN, | |
3336 | + .name = "S-Video", | |
3337 | + }, | |
3338 | + { | |
3339 | + .video_input = 3, | |
3340 | + .audio_input = TVAUDIO_INPUT_TUNER, | |
3341 | + .name = "Tuner", | |
3342 | + }, | |
3343 | + }, | |
3344 | + }, | |
3345 | +}; | |
3346 | + | |
3347 | +static struct go7007_usb_board board_xmen = { | |
3348 | + .flags = 0, | |
3349 | + .main_info = { | |
3350 | + .firmware = "go7007tv.bin", | |
3351 | + .flags = GO7007_BOARD_USE_ONBOARD_I2C, | |
3352 | + .hpi_buffer_cap = 0, | |
3353 | + .sensor_flags = GO7007_SENSOR_VREF_POLAR, | |
3354 | + .sensor_width = 320, | |
3355 | + .sensor_height = 240, | |
3356 | + .sensor_framerate = 30030, | |
3357 | + .audio_flags = GO7007_AUDIO_ONE_CHANNEL | | |
3358 | + GO7007_AUDIO_I2S_MODE_3 | | |
3359 | + GO7007_AUDIO_WORD_14 | | |
3360 | + GO7007_AUDIO_I2S_MASTER | | |
3361 | + GO7007_AUDIO_BCLK_POLAR | | |
3362 | + GO7007_AUDIO_OKI_MODE, | |
3363 | + .audio_rate = 8000, | |
3364 | + .audio_bclk_div = 48, | |
3365 | + .audio_main_div = 1, | |
3366 | + .num_i2c_devs = 1, | |
3367 | + .i2c_devs = { | |
3368 | + { | |
3369 | + .id = I2C_DRIVERID_WIS_OV7640, | |
3370 | + .addr = 0x21, | |
3371 | + }, | |
3372 | + }, | |
3373 | + .num_inputs = 1, | |
3374 | + .inputs = { | |
3375 | + { | |
3376 | + .name = "Camera", | |
3377 | + }, | |
3378 | + }, | |
3379 | + }, | |
3380 | +}; | |
3381 | + | |
3382 | +static struct go7007_usb_board board_matrix_revolution = { | |
3383 | + .flags = GO7007_USB_EZUSB, | |
3384 | + .main_info = { | |
3385 | + .firmware = "go7007tv.bin", | |
3386 | + .flags = GO7007_BOARD_HAS_AUDIO | | |
3387 | + GO7007_BOARD_USE_ONBOARD_I2C, | |
3388 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3389 | + GO7007_AUDIO_I2S_MASTER | | |
3390 | + GO7007_AUDIO_WORD_16, | |
3391 | + .audio_rate = 48000, | |
3392 | + .audio_bclk_div = 8, | |
3393 | + .audio_main_div = 2, | |
3394 | + .hpi_buffer_cap = 7, | |
3395 | + .sensor_flags = GO7007_SENSOR_656 | | |
3396 | + GO7007_SENSOR_TV | | |
3397 | + GO7007_SENSOR_VBI, | |
3398 | + .num_i2c_devs = 1, | |
3399 | + .i2c_devs = { | |
3400 | + { | |
3401 | + .id = I2C_DRIVERID_WIS_TW9903, | |
3402 | + .addr = 0x44, | |
3403 | + }, | |
3404 | + }, | |
3405 | + .num_inputs = 2, | |
3406 | + .inputs = { | |
3407 | + { | |
3408 | + .video_input = 2, | |
3409 | + .name = "Composite", | |
3410 | + }, | |
3411 | + { | |
3412 | + .video_input = 8, | |
3413 | + .name = "S-Video", | |
3414 | + }, | |
3415 | + }, | |
3416 | + }, | |
3417 | +}; | |
3418 | + | |
3419 | +static struct go7007_usb_board board_lifeview_lr192 = { | |
3420 | + .flags = GO7007_USB_EZUSB, | |
3421 | + .main_info = { | |
3422 | + .firmware = "go7007tv.bin", | |
3423 | + .flags = GO7007_BOARD_HAS_AUDIO | | |
3424 | + GO7007_BOARD_USE_ONBOARD_I2C, | |
3425 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3426 | + GO7007_AUDIO_WORD_16, | |
3427 | + .audio_rate = 48000, | |
3428 | + .audio_bclk_div = 8, | |
3429 | + .audio_main_div = 2, | |
3430 | + .hpi_buffer_cap = 7, | |
3431 | + .sensor_flags = GO7007_SENSOR_656 | | |
3432 | + GO7007_SENSOR_VALID_ENABLE | | |
3433 | + GO7007_SENSOR_TV | | |
3434 | + GO7007_SENSOR_VBI | | |
3435 | + GO7007_SENSOR_SCALING, | |
3436 | + .num_i2c_devs = 0, | |
3437 | + .num_inputs = 1, | |
3438 | + .inputs = { | |
3439 | + { | |
3440 | + .video_input = 0, | |
3441 | + .name = "Composite", | |
3442 | + }, | |
3443 | + }, | |
3444 | + }, | |
3445 | +}; | |
3446 | + | |
3447 | +static struct go7007_usb_board board_endura = { | |
3448 | + .flags = 0, | |
3449 | + .main_info = { | |
3450 | + .firmware = "go7007tv.bin", | |
3451 | + .flags = 0, | |
3452 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3453 | + GO7007_AUDIO_I2S_MASTER | | |
3454 | + GO7007_AUDIO_WORD_16, | |
3455 | + .audio_rate = 8000, | |
3456 | + .audio_bclk_div = 48, | |
3457 | + .audio_main_div = 8, | |
3458 | + .hpi_buffer_cap = 0, | |
3459 | + .sensor_flags = GO7007_SENSOR_656 | | |
3460 | + GO7007_SENSOR_TV, | |
3461 | + .sensor_h_offset = 8, | |
3462 | + .num_i2c_devs = 0, | |
3463 | + .num_inputs = 1, | |
3464 | + .inputs = { | |
3465 | + { | |
3466 | + .name = "Camera", | |
3467 | + }, | |
3468 | + }, | |
3469 | + }, | |
3470 | +}; | |
3471 | + | |
3472 | +static struct go7007_usb_board board_adlink_mpg24 = { | |
3473 | + .flags = 0, | |
3474 | + .main_info = { | |
3475 | + .firmware = "go7007tv.bin", | |
3476 | + .flags = GO7007_BOARD_USE_ONBOARD_I2C, | |
3477 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
3478 | + GO7007_AUDIO_I2S_MASTER | | |
3479 | + GO7007_AUDIO_WORD_16, | |
3480 | + .audio_rate = 48000, | |
3481 | + .audio_bclk_div = 8, | |
3482 | + .audio_main_div = 2, | |
3483 | + .hpi_buffer_cap = 0, | |
3484 | + .sensor_flags = GO7007_SENSOR_656 | | |
3485 | + GO7007_SENSOR_TV | | |
3486 | + GO7007_SENSOR_VBI, | |
3487 | + .num_i2c_devs = 1, | |
3488 | + .i2c_devs = { | |
3489 | + { | |
3490 | + .id = I2C_DRIVERID_WIS_TW2804, | |
3491 | + .addr = 0x00, /* yes, really */ | |
3492 | + }, | |
3493 | + }, | |
3494 | + .num_inputs = 1, | |
3495 | + .inputs = { | |
3496 | + { | |
3497 | + .name = "Composite", | |
3498 | + }, | |
3499 | + }, | |
3500 | + }, | |
3501 | +}; | |
3502 | + | |
3503 | +static struct usb_device_id go7007_usb_id_table[] = { | |
3504 | + { | |
3505 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | | |
3506 | + USB_DEVICE_ID_MATCH_INT_INFO, | |
3507 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3508 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3509 | + .bcdDevice_lo = 0x200, /* Revision number of XMen */ | |
3510 | + .bcdDevice_hi = 0x200, | |
3511 | + .bInterfaceClass = 255, | |
3512 | + .bInterfaceSubClass = 0, | |
3513 | + .bInterfaceProtocol = 255, | |
3514 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN, | |
3515 | + }, | |
3516 | + { | |
3517 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3518 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3519 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3520 | + .bcdDevice_lo = 0x202, /* Revision number of Matrix II */ | |
3521 | + .bcdDevice_hi = 0x202, | |
3522 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II, | |
3523 | + }, | |
3524 | + { | |
3525 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3526 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3527 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3528 | + .bcdDevice_lo = 0x204, /* Revision number of Matrix */ | |
3529 | + .bcdDevice_hi = 0x204, /* Reloaded */ | |
3530 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD, | |
3531 | + }, | |
3532 | + { | |
3533 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | | |
3534 | + USB_DEVICE_ID_MATCH_INT_INFO, | |
3535 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3536 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3537 | + .bcdDevice_lo = 0x205, /* Revision number of XMen-II */ | |
3538 | + .bcdDevice_hi = 0x205, | |
3539 | + .bInterfaceClass = 255, | |
3540 | + .bInterfaceSubClass = 0, | |
3541 | + .bInterfaceProtocol = 255, | |
3542 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II, | |
3543 | + }, | |
3544 | + { | |
3545 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3546 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3547 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3548 | + .bcdDevice_lo = 0x208, /* Revision number of Star Trek */ | |
3549 | + .bcdDevice_hi = 0x208, | |
3550 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK, | |
3551 | + }, | |
3552 | + { | |
3553 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | | |
3554 | + USB_DEVICE_ID_MATCH_INT_INFO, | |
3555 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3556 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3557 | + .bcdDevice_lo = 0x209, /* Revision number of XMen-III */ | |
3558 | + .bcdDevice_hi = 0x209, | |
3559 | + .bInterfaceClass = 255, | |
3560 | + .bInterfaceSubClass = 0, | |
3561 | + .bInterfaceProtocol = 255, | |
3562 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III, | |
3563 | + }, | |
3564 | + { | |
3565 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3566 | + .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ | |
3567 | + .idProduct = 0x7007, /* Product ID of GO7007SB chip */ | |
3568 | + .bcdDevice_lo = 0x210, /* Revision number of Matrix */ | |
3569 | + .bcdDevice_hi = 0x210, /* Revolution */ | |
3570 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV, | |
3571 | + }, | |
3572 | + { | |
3573 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3574 | + .idVendor = 0x093b, /* Vendor ID of Plextor */ | |
3575 | + .idProduct = 0xa102, /* Product ID of M402U */ | |
3576 | + .bcdDevice_lo = 0x1, /* revision number of Blueberry */ | |
3577 | + .bcdDevice_hi = 0x1, | |
3578 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U, | |
3579 | + }, | |
3580 | + { | |
3581 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3582 | + .idVendor = 0x093b, /* Vendor ID of Plextor */ | |
3583 | + .idProduct = 0xa104, /* Product ID of TV402U */ | |
3584 | + .bcdDevice_lo = 0x1, | |
3585 | + .bcdDevice_hi = 0x1, | |
3586 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY, | |
3587 | + }, | |
3588 | + { | |
3589 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, | |
3590 | + .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */ | |
3591 | + .idProduct = 0xde00, /* Product ID of Lifeview LR192 */ | |
3592 | + .bcdDevice_lo = 0x1, | |
3593 | + .bcdDevice_hi = 0x1, | |
3594 | + .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192, | |
3595 | + }, | |
3596 | + { } /* Terminating entry */ | |
3597 | +}; | |
3598 | + | |
3599 | +MODULE_DEVICE_TABLE(usb, go7007_usb_id_table); | |
3600 | + | |
3601 | +/********************* Driver for EZ-USB HPI interface *********************/ | |
3602 | + | |
3603 | +static int go7007_usb_vendor_request(struct go7007 *go, int request, | |
3604 | + int value, int index, void *transfer_buffer, int length, int in) | |
3605 | +{ | |
3606 | + struct go7007_usb *usb = go->hpi_context; | |
3607 | + int timeout = 5000; | |
3608 | + | |
3609 | + if (in) { | |
3610 | + return usb_control_msg(usb->usbdev, | |
3611 | + usb_rcvctrlpipe(usb->usbdev, 0), request, | |
3612 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | |
3613 | + value, index, transfer_buffer, length, timeout); | |
3614 | + } else { | |
3615 | + return usb_control_msg(usb->usbdev, | |
3616 | + usb_sndctrlpipe(usb->usbdev, 0), request, | |
3617 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
3618 | + value, index, transfer_buffer, length, timeout); | |
3619 | + } | |
3620 | +} | |
3621 | + | |
3622 | +static int go7007_usb_interface_reset(struct go7007 *go) | |
3623 | +{ | |
3624 | + struct go7007_usb *usb = go->hpi_context; | |
3625 | + u16 intr_val, intr_data; | |
3626 | + | |
3627 | + /* Reset encoder */ | |
3628 | + if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) | |
3629 | + return -1; | |
3630 | + msleep(100); | |
3631 | + | |
3632 | + if (usb->board->flags & GO7007_USB_EZUSB) { | |
3633 | + /* Reset buffer in EZ-USB */ | |
3634 | +#ifdef GO7007_USB_DEBUG | |
3635 | + printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n"); | |
3636 | +#endif | |
3637 | + if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || | |
3638 | + go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) | |
3639 | + return -1; | |
3640 | + | |
3641 | + /* Reset encoder again */ | |
3642 | + if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) | |
3643 | + return -1; | |
3644 | + msleep(100); | |
3645 | + } | |
3646 | + | |
3647 | + /* Wait for an interrupt to indicate successful hardware reset */ | |
3648 | + if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || | |
3649 | + (intr_val & ~0x1) != 0x55aa) { | |
3650 | + printk(KERN_ERR | |
3651 | + "go7007-usb: unable to reset the USB interface\n"); | |
3652 | + return -1; | |
3653 | + } | |
3654 | + return 0; | |
3655 | +} | |
3656 | + | |
3657 | +static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, | |
3658 | + int addr, int data) | |
3659 | +{ | |
3660 | + struct go7007_usb *usb = go->hpi_context; | |
3661 | + int i, r; | |
3662 | + u16 status_reg; | |
3663 | + int timeout = 500; | |
3664 | + | |
3665 | +#ifdef GO7007_USB_DEBUG | |
3666 | + printk(KERN_DEBUG | |
3667 | + "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); | |
3668 | +#endif | |
3669 | + | |
3670 | + for (i = 0; i < 100; ++i) { | |
3671 | + r = usb_control_msg(usb->usbdev, | |
3672 | + usb_rcvctrlpipe(usb->usbdev, 0), 0x14, | |
3673 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | |
3674 | + 0, HPI_STATUS_ADDR, &status_reg, | |
3675 | + sizeof(status_reg), timeout); | |
3676 | + if (r < 0) | |
3677 | + goto write_int_error; | |
3678 | + __le16_to_cpus(&status_reg); | |
3679 | + if (!(status_reg & 0x0010)) | |
3680 | + break; | |
3681 | + msleep(10); | |
3682 | + } | |
3683 | + if (i == 100) { | |
3684 | + printk(KERN_ERR | |
3685 | + "go7007-usb: device is hung, status reg = 0x%04x\n", | |
3686 | + status_reg); | |
3687 | + return -1; | |
3688 | + } | |
3689 | + r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12, | |
3690 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, data, | |
3691 | + INT_PARAM_ADDR, NULL, 0, timeout); | |
3692 | + if (r < 0) | |
3693 | + goto write_int_error; | |
3694 | + r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), | |
3695 | + 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr, | |
3696 | + INT_INDEX_ADDR, NULL, 0, timeout); | |
3697 | + if (r < 0) | |
3698 | + goto write_int_error; | |
3699 | + return 0; | |
3700 | + | |
3701 | +write_int_error: | |
3702 | + printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); | |
3703 | + return r; | |
3704 | +} | |
3705 | + | |
3706 | +static int go7007_usb_onboard_write_interrupt(struct go7007 *go, | |
3707 | + int addr, int data) | |
3708 | +{ | |
3709 | + struct go7007_usb *usb = go->hpi_context; | |
3710 | + u8 *tbuf; | |
3711 | + int r; | |
3712 | + int timeout = 500; | |
3713 | + | |
3714 | +#ifdef GO7007_USB_DEBUG | |
3715 | + printk(KERN_DEBUG | |
3716 | + "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); | |
3717 | +#endif | |
3718 | + | |
3719 | + tbuf = kmalloc(8, GFP_KERNEL); | |
3720 | + if (tbuf == NULL) | |
3721 | + return -ENOMEM; | |
3722 | + memset(tbuf, 0, 8); | |
3723 | + tbuf[0] = data & 0xff; | |
3724 | + tbuf[1] = data >> 8; | |
3725 | + tbuf[2] = addr & 0xff; | |
3726 | + tbuf[3] = addr >> 8; | |
3727 | + r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00, | |
3728 | + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, | |
3729 | + 0xf0f0, tbuf, 8, timeout); | |
3730 | + kfree(tbuf); | |
3731 | + if (r < 0) { | |
3732 | + printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); | |
3733 | + return r; | |
3734 | + } | |
3735 | + return 0; | |
3736 | +} | |
3737 | + | |
3738 | +static void go7007_usb_readinterrupt_complete(struct urb *urb) | |
3739 | +{ | |
3740 | + struct go7007 *go = (struct go7007 *)urb->context; | |
3741 | + u16 *regs = (u16 *)urb->transfer_buffer; | |
3742 | + | |
3743 | + if (urb->status != 0) { | |
3744 | + if (urb->status != -ESHUTDOWN && | |
3745 | + go->status != STATUS_SHUTDOWN) { | |
3746 | + printk(KERN_ERR | |
3747 | + "go7007-usb: error in read interrupt: %d\n", | |
3748 | + urb->status); | |
3749 | + } else { | |
3750 | + wake_up(&go->interrupt_waitq); | |
3751 | + return; | |
3752 | + } | |
3753 | + } else if (urb->actual_length != urb->transfer_buffer_length) { | |
3754 | + printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n"); | |
3755 | + } else { | |
3756 | + go->interrupt_available = 1; | |
3757 | + go->interrupt_data = __le16_to_cpu(regs[0]); | |
3758 | + go->interrupt_value = __le16_to_cpu(regs[1]); | |
3759 | +#ifdef GO7007_USB_DEBUG | |
3760 | + printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n", | |
3761 | + go->interrupt_value, go->interrupt_data); | |
3762 | +#endif | |
3763 | + } | |
3764 | + | |
3765 | + wake_up(&go->interrupt_waitq); | |
3766 | +} | |
3767 | + | |
3768 | +static int go7007_usb_read_interrupt(struct go7007 *go) | |
3769 | +{ | |
3770 | + struct go7007_usb *usb = go->hpi_context; | |
3771 | + int r; | |
3772 | + | |
3773 | + r = usb_submit_urb(usb->intr_urb, GFP_KERNEL); | |
3774 | + if (r < 0) { | |
3775 | + printk(KERN_ERR | |
3776 | + "go7007-usb: unable to submit interrupt urb: %d\n", r); | |
3777 | + return r; | |
3778 | + } | |
3779 | + return 0; | |
3780 | +} | |
3781 | + | |
3782 | +static void go7007_usb_read_video_pipe_complete(struct urb *urb) | |
3783 | +{ | |
3784 | + struct go7007 *go = (struct go7007 *)urb->context; | |
3785 | + int r; | |
3786 | + | |
3787 | + if (!go->streaming) { | |
3788 | + wake_up_interruptible(&go->frame_waitq); | |
3789 | + return; | |
3790 | + } | |
3791 | + if (urb->status != 0) { | |
3792 | + printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", | |
3793 | + urb->status); | |
3794 | + return; | |
3795 | + } | |
3796 | + if (urb->actual_length != urb->transfer_buffer_length) { | |
3797 | + printk(KERN_ERR "go7007-usb: short read in video pipe!\n"); | |
3798 | + return; | |
3799 | + } | |
3800 | + go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length); | |
3801 | + r = usb_submit_urb(urb, GFP_ATOMIC); | |
3802 | + if (r < 0) | |
3803 | + printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r); | |
3804 | +} | |
3805 | + | |
3806 | +static void go7007_usb_read_audio_pipe_complete(struct urb *urb) | |
3807 | +{ | |
3808 | + struct go7007 *go = (struct go7007 *)urb->context; | |
3809 | + int r; | |
3810 | + | |
3811 | + if (!go->streaming) | |
3812 | + return; | |
3813 | + if (urb->status != 0) { | |
3814 | + printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", | |
3815 | + urb->status); | |
3816 | + return; | |
3817 | + } | |
3818 | + if (urb->actual_length != urb->transfer_buffer_length) { | |
3819 | + printk(KERN_ERR "go7007-usb: short read in audio pipe!\n"); | |
3820 | + return; | |
3821 | + } | |
3822 | + if (go->audio_deliver != NULL) | |
3823 | + go->audio_deliver(go, urb->transfer_buffer, urb->actual_length); | |
3824 | + r = usb_submit_urb(urb, GFP_ATOMIC); | |
3825 | + if (r < 0) | |
3826 | + printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r); | |
3827 | +} | |
3828 | + | |
3829 | +static int go7007_usb_stream_start(struct go7007 *go) | |
3830 | +{ | |
3831 | + struct go7007_usb *usb = go->hpi_context; | |
3832 | + int i, r; | |
3833 | + | |
3834 | + for (i = 0; i < 8; ++i) { | |
3835 | + r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL); | |
3836 | + if (r < 0) { | |
3837 | + printk(KERN_ERR "go7007-usb: error submitting video " | |
3838 | + "urb %d: %d\n", i, r); | |
3839 | + goto video_submit_failed; | |
3840 | + } | |
3841 | + } | |
3842 | + if (!go->audio_enabled) | |
3843 | + return 0; | |
3844 | + | |
3845 | + for (i = 0; i < 8; ++i) { | |
3846 | + r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL); | |
3847 | + if (r < 0) { | |
3848 | + printk(KERN_ERR "go7007-usb: error submitting audio " | |
3849 | + "urb %d: %d\n", i, r); | |
3850 | + goto audio_submit_failed; | |
3851 | + } | |
3852 | + } | |
3853 | + return 0; | |
3854 | + | |
3855 | +audio_submit_failed: | |
3856 | + for (i = 0; i < 8; ++i) | |
3857 | + usb_kill_urb(usb->audio_urbs[i]); | |
3858 | +video_submit_failed: | |
3859 | + for (i = 0; i < 8; ++i) | |
3860 | + usb_kill_urb(usb->video_urbs[i]); | |
3861 | + return -1; | |
3862 | +} | |
3863 | + | |
3864 | +static int go7007_usb_stream_stop(struct go7007 *go) | |
3865 | +{ | |
3866 | + struct go7007_usb *usb = go->hpi_context; | |
3867 | + int i; | |
3868 | + | |
3869 | + if (go->status == STATUS_SHUTDOWN) | |
3870 | + return 0; | |
3871 | + for (i = 0; i < 8; ++i) | |
3872 | + usb_kill_urb(usb->video_urbs[i]); | |
3873 | + if (go->audio_enabled) | |
3874 | + for (i = 0; i < 8; ++i) | |
3875 | + usb_kill_urb(usb->audio_urbs[i]); | |
3876 | + return 0; | |
3877 | +} | |
3878 | + | |
3879 | +static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) | |
3880 | +{ | |
3881 | + struct go7007_usb *usb = go->hpi_context; | |
3882 | + int transferred, pipe; | |
3883 | + int timeout = 500; | |
3884 | + | |
3885 | +#ifdef GO7007_USB_DEBUG | |
3886 | + printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len); | |
3887 | +#endif | |
3888 | + | |
3889 | + if (usb->board->flags & GO7007_USB_EZUSB) | |
3890 | + pipe = usb_sndbulkpipe(usb->usbdev, 2); | |
3891 | + else | |
3892 | + pipe = usb_sndbulkpipe(usb->usbdev, 3); | |
3893 | + | |
3894 | + return usb_bulk_msg(usb->usbdev, pipe, data, len, | |
3895 | + &transferred, timeout); | |
3896 | +} | |
3897 | + | |
3898 | +static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { | |
3899 | + .interface_reset = go7007_usb_interface_reset, | |
3900 | + .write_interrupt = go7007_usb_ezusb_write_interrupt, | |
3901 | + .read_interrupt = go7007_usb_read_interrupt, | |
3902 | + .stream_start = go7007_usb_stream_start, | |
3903 | + .stream_stop = go7007_usb_stream_stop, | |
3904 | + .send_firmware = go7007_usb_send_firmware, | |
3905 | +}; | |
3906 | + | |
3907 | +static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { | |
3908 | + .interface_reset = go7007_usb_interface_reset, | |
3909 | + .write_interrupt = go7007_usb_onboard_write_interrupt, | |
3910 | + .read_interrupt = go7007_usb_read_interrupt, | |
3911 | + .stream_start = go7007_usb_stream_start, | |
3912 | + .stream_stop = go7007_usb_stream_stop, | |
3913 | + .send_firmware = go7007_usb_send_firmware, | |
3914 | +}; | |
3915 | + | |
3916 | +/********************* Driver for EZ-USB I2C adapter *********************/ | |
3917 | + | |
3918 | +static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, | |
3919 | + struct i2c_msg msgs[], int num) | |
3920 | +{ | |
3921 | + struct go7007 *go = i2c_get_adapdata(adapter); | |
3922 | + struct go7007_usb *usb = go->hpi_context; | |
3923 | + u8 buf[16]; | |
3924 | + int buf_len, i; | |
3925 | + int ret = -1; | |
3926 | + | |
3927 | + if (go->status == STATUS_SHUTDOWN) | |
3928 | + return -1; | |
3929 | + | |
3930 | + down(&usb->i2c_lock); | |
3931 | + | |
3932 | + for (i = 0; i < num; ++i) { | |
3933 | + /* The hardware command is "write some bytes then read some | |
3934 | + * bytes", so we try to coalesce a write followed by a read | |
3935 | + * into a single USB transaction */ | |
3936 | + if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr && | |
3937 | + !(msgs[i].flags & I2C_M_RD) && | |
3938 | + (msgs[i + 1].flags & I2C_M_RD)) { | |
3939 | +#ifdef GO7007_I2C_DEBUG | |
3940 | + printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d " | |
3941 | + "bytes on %02x\n", msgs[i].len, | |
3942 | + msgs[i + 1].len, msgs[i].addr); | |
3943 | +#endif | |
3944 | + buf[0] = 0x01; | |
3945 | + buf[1] = msgs[i].len + 1; | |
3946 | + buf[2] = msgs[i].addr << 1; | |
3947 | + memcpy(&buf[3], msgs[i].buf, msgs[i].len); | |
3948 | + buf_len = msgs[i].len + 3; | |
3949 | + buf[buf_len++] = msgs[++i].len; | |
3950 | + } else if (msgs[i].flags & I2C_M_RD) { | |
3951 | +#ifdef GO7007_I2C_DEBUG | |
3952 | + printk(KERN_DEBUG "go7007-usb: i2c read %d " | |
3953 | + "bytes on %02x\n", msgs[i].len, | |
3954 | + msgs[i].addr); | |
3955 | +#endif | |
3956 | + buf[0] = 0x01; | |
3957 | + buf[1] = 1; | |
3958 | + buf[2] = msgs[i].addr << 1; | |
3959 | + buf[3] = msgs[i].len; | |
3960 | + buf_len = 4; | |
3961 | + } else { | |
3962 | +#ifdef GO7007_I2C_DEBUG | |
3963 | + printk(KERN_DEBUG "go7007-usb: i2c write %d " | |
3964 | + "bytes on %02x\n", msgs[i].len, | |
3965 | + msgs[i].addr); | |
3966 | +#endif | |
3967 | + buf[0] = 0x00; | |
3968 | + buf[1] = msgs[i].len + 1; | |
3969 | + buf[2] = msgs[i].addr << 1; | |
3970 | + memcpy(&buf[3], msgs[i].buf, msgs[i].len); | |
3971 | + buf_len = msgs[i].len + 3; | |
3972 | + buf[buf_len++] = 0; | |
3973 | + } | |
3974 | + if (go7007_usb_vendor_request(go, 0x24, 0, 0, | |
3975 | + buf, buf_len, 0) < 0) | |
3976 | + goto i2c_done; | |
3977 | + if (msgs[i].flags & I2C_M_RD) { | |
3978 | + memset(buf, 0, sizeof(buf)); | |
3979 | + if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf, | |
3980 | + msgs[i].len + 1, 1) < 0) | |
3981 | + goto i2c_done; | |
3982 | + memcpy(msgs[i].buf, buf + 1, msgs[i].len); | |
3983 | + } | |
3984 | + } | |
3985 | + ret = 0; | |
3986 | + | |
3987 | +i2c_done: | |
3988 | + up(&usb->i2c_lock); | |
3989 | + return ret; | |
3990 | +} | |
3991 | + | |
3992 | +static u32 go7007_usb_functionality(struct i2c_adapter *adapter) | |
3993 | +{ | |
3994 | + /* No errors are reported by the hardware, so we don't bother | |
3995 | + * supporting quick writes to avoid confusing probing */ | |
3996 | + return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; | |
3997 | +} | |
3998 | + | |
3999 | +static struct i2c_algorithm go7007_usb_algo = { | |
4000 | + .master_xfer = go7007_usb_i2c_master_xfer, | |
4001 | + .functionality = go7007_usb_functionality, | |
4002 | +}; | |
4003 | + | |
4004 | +static struct i2c_adapter go7007_usb_adap_templ = { | |
4005 | + .owner = THIS_MODULE, | |
4006 | + .class = I2C_CLASS_TV_ANALOG, | |
4007 | + .name = "WIS GO7007SB EZ-USB", | |
4008 | + .id = I2C_ALGO_GO7007_USB, | |
4009 | + .algo = &go7007_usb_algo, | |
4010 | +}; | |
4011 | + | |
4012 | +/********************* USB add/remove functions *********************/ | |
4013 | + | |
4014 | +static int go7007_usb_probe(struct usb_interface *intf, | |
4015 | + const struct usb_device_id *id) | |
4016 | +{ | |
4017 | + struct go7007 *go; | |
4018 | + struct go7007_usb *usb; | |
4019 | + struct go7007_usb_board *board; | |
4020 | + struct usb_device *usbdev = interface_to_usbdev(intf); | |
4021 | + char *name; | |
4022 | + int video_pipe, i, v_urb_len; | |
4023 | + | |
4024 | + printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n"); | |
4025 | + | |
4026 | + switch (id->driver_info) { | |
4027 | + case GO7007_BOARDID_MATRIX_II: | |
4028 | + name = "WIS Matrix II or compatible"; | |
4029 | + board = &board_matrix_ii; | |
4030 | + break; | |
4031 | + case GO7007_BOARDID_MATRIX_RELOAD: | |
4032 | + name = "WIS Matrix Reloaded or compatible"; | |
4033 | + board = &board_matrix_reload; | |
4034 | + break; | |
4035 | + case GO7007_BOARDID_MATRIX_REV: | |
4036 | + name = "WIS Matrix Revolution or compatible"; | |
4037 | + board = &board_matrix_revolution; | |
4038 | + break; | |
4039 | + case GO7007_BOARDID_STAR_TREK: | |
4040 | + name = "WIS Star Trek or compatible"; | |
4041 | + board = &board_star_trek; | |
4042 | + break; | |
4043 | + case GO7007_BOARDID_XMEN: | |
4044 | + name = "WIS XMen or compatible"; | |
4045 | + board = &board_xmen; | |
4046 | + break; | |
4047 | + case GO7007_BOARDID_XMEN_II: | |
4048 | + name = "WIS XMen II or compatible"; | |
4049 | + board = &board_xmen; | |
4050 | + break; | |
4051 | + case GO7007_BOARDID_XMEN_III: | |
4052 | + name = "WIS XMen III or compatible"; | |
4053 | + board = &board_xmen; | |
4054 | + break; | |
4055 | + case GO7007_BOARDID_PX_M402U: | |
4056 | + name = "Plextor PX-M402U"; | |
4057 | + board = &board_matrix_ii; | |
4058 | + break; | |
4059 | + case GO7007_BOARDID_PX_TV402U_ANY: | |
4060 | + name = "Plextor PX-TV402U (unknown tuner)"; | |
4061 | + board = &board_px_tv402u; | |
4062 | + break; | |
4063 | + case GO7007_BOARDID_LIFEVIEW_LR192: | |
4064 | + printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra " | |
4065 | + "is not supported. Sorry!\n"); | |
4066 | + return 0; | |
4067 | + name = "Lifeview TV Walker Ultra"; | |
4068 | + board = &board_lifeview_lr192; | |
4069 | + break; | |
4070 | + default: | |
4071 | + printk(KERN_ERR "go7007-usb: unknown board ID %d!\n", | |
4072 | + (unsigned int)id->driver_info); | |
4073 | + return 0; | |
4074 | + } | |
4075 | + | |
4076 | + usb = kmalloc(sizeof(struct go7007_usb), GFP_KERNEL); | |
4077 | + if (usb == NULL) | |
4078 | + return -ENOMEM; | |
4079 | + memset(usb, 0, sizeof(struct go7007_usb)); | |
4080 | + | |
4081 | + /* Allocate the URB and buffer for receiving incoming interrupts */ | |
4082 | + usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | |
4083 | + if (usb->intr_urb == NULL) | |
4084 | + goto allocfail; | |
4085 | + usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); | |
4086 | + if (usb->intr_urb->transfer_buffer == NULL) | |
4087 | + goto allocfail; | |
4088 | + | |
4089 | + go = go7007_alloc(&board->main_info, &intf->dev); | |
4090 | + if (go == NULL) | |
4091 | + goto allocfail; | |
4092 | + usb->board = board; | |
4093 | + usb->usbdev = usbdev; | |
4094 | + go->board_id = id->driver_info; | |
4095 | + strncpy(go->name, name, sizeof(go->name)); | |
4096 | + if (board->flags & GO7007_USB_EZUSB) | |
4097 | + go->hpi_ops = &go7007_usb_ezusb_hpi_ops; | |
4098 | + else | |
4099 | + go->hpi_ops = &go7007_usb_onboard_hpi_ops; | |
4100 | + go->hpi_context = usb; | |
4101 | + usb_fill_int_urb(usb->intr_urb, usb->usbdev, | |
4102 | + usb_rcvintpipe(usb->usbdev, 4), | |
4103 | + usb->intr_urb->transfer_buffer, 2*sizeof(u16), | |
4104 | + go7007_usb_readinterrupt_complete, go, 8); | |
4105 | + usb_set_intfdata(intf, go); | |
4106 | + | |
4107 | + /* Boot the GO7007 */ | |
4108 | + if (go7007_boot_encoder(go, go->board_info->flags & | |
4109 | + GO7007_BOARD_USE_ONBOARD_I2C) < 0) | |
4110 | + goto initfail; | |
4111 | + | |
4112 | + /* Register the EZ-USB I2C adapter, if we're using it */ | |
4113 | + if (board->flags & GO7007_USB_EZUSB_I2C) { | |
4114 | + memcpy(&go->i2c_adapter, &go7007_usb_adap_templ, | |
4115 | + sizeof(go7007_usb_adap_templ)); | |
4116 | + init_MUTEX(&usb->i2c_lock); | |
4117 | + go->i2c_adapter.dev.parent = go->dev; | |
4118 | + i2c_set_adapdata(&go->i2c_adapter, go); | |
4119 | + if (i2c_add_adapter(&go->i2c_adapter) < 0) { | |
4120 | + printk(KERN_ERR | |
4121 | + "go7007-usb: error: i2c_add_adapter failed\n"); | |
4122 | + goto initfail; | |
4123 | + } | |
4124 | + go->i2c_adapter_online = 1; | |
4125 | + } | |
4126 | + | |
4127 | + /* Pelco and Adlink reused the XMen and XMen-III vendor and product | |
4128 | + * IDs for their own incompatible designs. We can detect XMen boards | |
4129 | + * by probing the sensor, but there is no way to probe the sensors on | |
4130 | + * the Pelco and Adlink designs so we default to the Adlink. If it | |
4131 | + * is actually a Pelco, the user must set the assume_endura module | |
4132 | + * parameter. */ | |
4133 | + if ((go->board_id == GO7007_BOARDID_XMEN || | |
4134 | + go->board_id == GO7007_BOARDID_XMEN_III) && | |
4135 | + go->i2c_adapter_online) { | |
4136 | + union i2c_smbus_data data; | |
4137 | + | |
4138 | + /* Check to see if register 0x0A is 0x76 */ | |
4139 | + i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB, | |
4140 | + I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data); | |
4141 | + if (data.byte != 0x76) { | |
4142 | + if (assume_endura) { | |
4143 | + go->board_id = GO7007_BOARDID_ENDURA; | |
4144 | + usb->board = board = &board_endura; | |
4145 | + go->board_info = &board->main_info; | |
4146 | + strncpy(go->name, "Pelco Endura", | |
4147 | + sizeof(go->name)); | |
4148 | + } else { | |
4149 | + u16 channel; | |
4150 | + | |
4151 | + /* set GPIO5 to be an output, currently low */ | |
4152 | + go7007_write_addr(go, 0x3c82, 0x0000); | |
4153 | + go7007_write_addr(go, 0x3c80, 0x00df); | |
4154 | + /* read channel number from GPIO[1:0] */ | |
4155 | + go7007_read_addr(go, 0x3c81, &channel); | |
4156 | + channel &= 0x3; | |
4157 | + go->board_id = GO7007_BOARDID_ADLINK_MPG24; | |
4158 | + usb->board = board = &board_adlink_mpg24; | |
4159 | + go->board_info = &board->main_info; | |
4160 | + go->channel_number = channel; | |
4161 | + snprintf(go->name, sizeof(go->name), | |
4162 | + "Adlink PCI-MPG24, channel #%d", | |
4163 | + channel); | |
4164 | + } | |
4165 | + } | |
4166 | + } | |
4167 | + | |
4168 | + /* Probe the tuner model on the TV402U */ | |
4169 | + if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { | |
4170 | + u8 data[3]; | |
4171 | + | |
4172 | + /* Board strapping indicates tuner model */ | |
4173 | + if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) { | |
4174 | + printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); | |
4175 | + goto initfail; | |
4176 | + } | |
4177 | + switch (data[0] >> 6) { | |
4178 | + case 1: | |
4179 | + go->board_id = GO7007_BOARDID_PX_TV402U_EU; | |
4180 | + go->tuner_type = TUNER_SONY_BTF_PG472Z; | |
4181 | + strncpy(go->name, "Plextor PX-TV402U-EU", | |
4182 | + sizeof(go->name)); | |
4183 | + break; | |
4184 | + case 2: | |
4185 | + go->board_id = GO7007_BOARDID_PX_TV402U_JP; | |
4186 | + go->tuner_type = TUNER_SONY_BTF_PK467Z; | |
4187 | + strncpy(go->name, "Plextor PX-TV402U-JP", | |
4188 | + sizeof(go->name)); | |
4189 | + break; | |
4190 | + case 3: | |
4191 | + go->board_id = GO7007_BOARDID_PX_TV402U_NA; | |
4192 | + go->tuner_type = TUNER_SONY_BTF_PB463Z; | |
4193 | + strncpy(go->name, "Plextor PX-TV402U-NA", | |
4194 | + sizeof(go->name)); | |
4195 | + break; | |
4196 | + default: | |
4197 | + printk(KERN_DEBUG "go7007-usb: unable to detect " | |
4198 | + "tuner type!\n"); | |
4199 | + break; | |
4200 | + } | |
4201 | + /* Configure tuner mode selection inputs connected | |
4202 | + * to the EZ-USB GPIO output pins */ | |
4203 | + if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, | |
4204 | + NULL, 0, 0) < 0) { | |
4205 | + printk(KERN_ERR | |
4206 | + "go7007-usb: GPIO write failed!\n"); | |
4207 | + goto initfail; | |
4208 | + } | |
4209 | + } | |
4210 | + | |
4211 | + /* Print a nasty message if the user attempts to use a USB2.0 device in | |
4212 | + * a USB1.1 port. There will be silent corruption of the stream. */ | |
4213 | + if ((board->flags & GO7007_USB_EZUSB) && | |
4214 | + usbdev->speed != USB_SPEED_HIGH) | |
4215 | + printk(KERN_ERR "go7007-usb: *** WARNING *** This device " | |
4216 | + "must be connected to a USB 2.0 port! " | |
4217 | + "Attempting to capture video through a USB 1.1 " | |
4218 | + "port will result in stream corruption, even " | |
4219 | + "at low bitrates!\n"); | |
4220 | + | |
4221 | + /* Do any final GO7007 initialization, then register the | |
4222 | + * V4L2 and ALSA interfaces */ | |
4223 | + if (go7007_register_encoder(go) < 0) | |
4224 | + goto initfail; | |
4225 | + | |
4226 | + /* Allocate the URBs and buffers for receiving the video stream */ | |
4227 | + if (board->flags & GO7007_USB_EZUSB) { | |
4228 | + v_urb_len = 1024; | |
4229 | + video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); | |
4230 | + } else { | |
4231 | + v_urb_len = 512; | |
4232 | + video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); | |
4233 | + } | |
4234 | + for (i = 0; i < 8; ++i) { | |
4235 | + usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); | |
4236 | + if (usb->video_urbs[i] == NULL) | |
4237 | + goto initfail; | |
4238 | + usb->video_urbs[i]->transfer_buffer = | |
4239 | + kmalloc(v_urb_len, GFP_KERNEL); | |
4240 | + if (usb->video_urbs[i]->transfer_buffer == NULL) | |
4241 | + goto initfail; | |
4242 | + usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe, | |
4243 | + usb->video_urbs[i]->transfer_buffer, v_urb_len, | |
4244 | + go7007_usb_read_video_pipe_complete, go); | |
4245 | + } | |
4246 | + | |
4247 | + /* Allocate the URBs and buffers for receiving the audio stream */ | |
4248 | + if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled) | |
4249 | + for (i = 0; i < 8; ++i) { | |
4250 | + usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); | |
4251 | + if (usb->audio_urbs[i] == NULL) | |
4252 | + goto initfail; | |
4253 | + usb->audio_urbs[i]->transfer_buffer = kmalloc(4096, | |
4254 | + GFP_KERNEL); | |
4255 | + if (usb->audio_urbs[i]->transfer_buffer == NULL) | |
4256 | + goto initfail; | |
4257 | + usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev, | |
4258 | + usb_rcvbulkpipe(usb->usbdev, 8), | |
4259 | + usb->audio_urbs[i]->transfer_buffer, 4096, | |
4260 | + go7007_usb_read_audio_pipe_complete, go); | |
4261 | + } | |
4262 | + | |
4263 | + | |
4264 | + go->status = STATUS_ONLINE; | |
4265 | + return 0; | |
4266 | + | |
4267 | +initfail: | |
4268 | + go->status = STATUS_SHUTDOWN; | |
4269 | + return 0; | |
4270 | + | |
4271 | +allocfail: | |
4272 | + if (usb->intr_urb) { | |
4273 | + kfree(usb->intr_urb->transfer_buffer); | |
4274 | + usb_free_urb(usb->intr_urb); | |
4275 | + } | |
4276 | + kfree(usb); | |
4277 | + return -ENOMEM; | |
4278 | +} | |
4279 | + | |
4280 | +static void go7007_usb_disconnect(struct usb_interface *intf) | |
4281 | +{ | |
4282 | + struct go7007 *go = usb_get_intfdata(intf); | |
4283 | + struct go7007_usb *usb = go->hpi_context; | |
4284 | + int i; | |
4285 | + | |
4286 | + go->status = STATUS_SHUTDOWN; | |
4287 | + usb_kill_urb(usb->intr_urb); | |
4288 | + | |
4289 | + /* Free USB-related structs */ | |
4290 | + for (i = 0; i < 8; ++i) { | |
4291 | + if (usb->video_urbs[i] != NULL) { | |
4292 | + if (usb->video_urbs[i]->transfer_buffer != NULL) | |
4293 | + kfree(usb->video_urbs[i]->transfer_buffer); | |
4294 | + usb_free_urb(usb->video_urbs[i]); | |
4295 | + } | |
4296 | + if (usb->audio_urbs[i] != NULL) { | |
4297 | + if (usb->audio_urbs[i]->transfer_buffer != NULL) | |
4298 | + kfree(usb->audio_urbs[i]->transfer_buffer); | |
4299 | + usb_free_urb(usb->audio_urbs[i]); | |
4300 | + } | |
4301 | + } | |
4302 | + kfree(usb->intr_urb->transfer_buffer); | |
4303 | + usb_free_urb(usb->intr_urb); | |
4304 | + | |
4305 | + kfree(go->hpi_context); | |
4306 | + | |
4307 | + go7007_remove(go); | |
4308 | +} | |
4309 | + | |
4310 | +static struct usb_driver go7007_usb_driver = { | |
4311 | + .name = "go7007", | |
4312 | + .probe = go7007_usb_probe, | |
4313 | + .disconnect = go7007_usb_disconnect, | |
4314 | + .id_table = go7007_usb_id_table, | |
4315 | +}; | |
4316 | + | |
4317 | +static int __init go7007_usb_init(void) | |
4318 | +{ | |
4319 | + return usb_register(&go7007_usb_driver); | |
4320 | +} | |
4321 | + | |
4322 | +static void __exit go7007_usb_cleanup(void) | |
4323 | +{ | |
4324 | + usb_deregister(&go7007_usb_driver); | |
4325 | +} | |
4326 | + | |
4327 | +module_init(go7007_usb_init); | |
4328 | +module_exit(go7007_usb_cleanup); | |
4329 | + | |
4330 | +MODULE_LICENSE("GPL v2"); | |
4331 | diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c | |
4332 | new file mode 100644 | |
4333 | index 0000000..d54d019 | |
4334 | --- /dev/null | |
4335 | +++ b/drivers/staging/go7007/go7007-v4l2.c | |
4336 | @@ -0,0 +1,1503 @@ | |
4337 | +/* | |
4338 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
4339 | + * | |
4340 | + * This program is free software; you can redistribute it and/or modify | |
4341 | + * it under the terms of the GNU General Public License (Version 2) as | |
4342 | + * published by the Free Software Foundation. | |
4343 | + * | |
4344 | + * This program is distributed in the hope that it will be useful, | |
4345 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
4346 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
4347 | + * GNU General Public License for more details. | |
4348 | + * | |
4349 | + * You should have received a copy of the GNU General Public License | |
4350 | + * along with this program; if not, write to the Free Software Foundation, | |
4351 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
4352 | + */ | |
4353 | + | |
4354 | +#include <linux/module.h> | |
4355 | +#include <linux/init.h> | |
4356 | +#include <linux/version.h> | |
4357 | +#include <linux/delay.h> | |
4358 | +#include <linux/sched.h> | |
4359 | +#include <linux/spinlock.h> | |
4360 | +#include <linux/fs.h> | |
4361 | +#include <linux/unistd.h> | |
4362 | +#include <linux/time.h> | |
4363 | +#include <linux/vmalloc.h> | |
4364 | +#include <linux/pagemap.h> | |
4365 | +#include <linux/videodev.h> | |
4366 | +#include <linux/video_decoder.h> | |
4367 | +#include <media/v4l2-common.h> | |
4368 | +#include <media/v4l2-ioctl.h> | |
4369 | +#include <linux/i2c.h> | |
4370 | +#include <linux/semaphore.h> | |
4371 | +#include <linux/uaccess.h> | |
4372 | +#include <asm/system.h> | |
4373 | + | |
4374 | +#include "go7007.h" | |
4375 | +#include "go7007-priv.h" | |
4376 | +#include "wis-i2c.h" | |
4377 | + | |
4378 | +static void deactivate_buffer(struct go7007_buffer *gobuf) | |
4379 | +{ | |
4380 | + int i; | |
4381 | + | |
4382 | + if (gobuf->state != BUF_STATE_IDLE) { | |
4383 | + list_del(&gobuf->stream); | |
4384 | + gobuf->state = BUF_STATE_IDLE; | |
4385 | + } | |
4386 | + if (gobuf->page_count > 0) { | |
4387 | + for (i = 0; i < gobuf->page_count; ++i) | |
4388 | + page_cache_release(gobuf->pages[i]); | |
4389 | + gobuf->page_count = 0; | |
4390 | + } | |
4391 | +} | |
4392 | + | |
4393 | +static void abort_queued(struct go7007 *go) | |
4394 | +{ | |
4395 | + struct go7007_buffer *gobuf, *next; | |
4396 | + | |
4397 | + list_for_each_entry_safe(gobuf, next, &go->stream, stream) { | |
4398 | + deactivate_buffer(gobuf); | |
4399 | + } | |
4400 | +} | |
4401 | + | |
4402 | +static int go7007_streamoff(struct go7007 *go) | |
4403 | +{ | |
4404 | + int retval = -EINVAL; | |
4405 | + unsigned long flags; | |
4406 | + | |
4407 | + down(&go->hw_lock); | |
4408 | + if (go->streaming) { | |
4409 | + go->streaming = 0; | |
4410 | + go7007_stream_stop(go); | |
4411 | + spin_lock_irqsave(&go->spinlock, flags); | |
4412 | + abort_queued(go); | |
4413 | + spin_unlock_irqrestore(&go->spinlock, flags); | |
4414 | + go7007_reset_encoder(go); | |
4415 | + retval = 0; | |
4416 | + } | |
4417 | + up(&go->hw_lock); | |
4418 | + return 0; | |
4419 | +} | |
4420 | + | |
4421 | +static int go7007_open(struct inode *inode, struct file *file) | |
4422 | +{ | |
4423 | + struct go7007 *go = video_get_drvdata(video_devdata(file)); | |
4424 | + struct go7007_file *gofh; | |
4425 | + | |
4426 | + if (go->status != STATUS_ONLINE) | |
4427 | + return -EBUSY; | |
4428 | + gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL); | |
4429 | + if (gofh == NULL) | |
4430 | + return -ENOMEM; | |
4431 | + ++go->ref_count; | |
4432 | + gofh->go = go; | |
4433 | + init_MUTEX(&gofh->lock); | |
4434 | + gofh->buf_count = 0; | |
4435 | + file->private_data = gofh; | |
4436 | + return 0; | |
4437 | +} | |
4438 | + | |
4439 | +static int go7007_release(struct inode *inode, struct file *file) | |
4440 | +{ | |
4441 | + struct go7007_file *gofh = file->private_data; | |
4442 | + struct go7007 *go = gofh->go; | |
4443 | + | |
4444 | + if (gofh->buf_count > 0) { | |
4445 | + go7007_streamoff(go); | |
4446 | + go->in_use = 0; | |
4447 | + kfree(gofh->bufs); | |
4448 | + gofh->buf_count = 0; | |
4449 | + } | |
4450 | + kfree(gofh); | |
4451 | + if (--go->ref_count == 0) | |
4452 | + kfree(go); | |
4453 | + file->private_data = NULL; | |
4454 | + return 0; | |
4455 | +} | |
4456 | + | |
4457 | +static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) | |
4458 | +{ | |
4459 | + u8 *f = page_address(gobuf->pages[0]); | |
4460 | + | |
4461 | + switch (format) { | |
4462 | + case GO7007_FORMAT_MJPEG: | |
4463 | + return V4L2_BUF_FLAG_KEYFRAME; | |
4464 | + case GO7007_FORMAT_MPEG4: | |
4465 | + switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { | |
4466 | + case 0: | |
4467 | + return V4L2_BUF_FLAG_KEYFRAME; | |
4468 | + case 1: | |
4469 | + return V4L2_BUF_FLAG_PFRAME; | |
4470 | + case 2: | |
4471 | + return V4L2_BUF_FLAG_BFRAME; | |
4472 | + default: | |
4473 | + return 0; | |
4474 | + } | |
4475 | + case GO7007_FORMAT_MPEG1: | |
4476 | + case GO7007_FORMAT_MPEG2: | |
4477 | + switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { | |
4478 | + case 1: | |
4479 | + return V4L2_BUF_FLAG_KEYFRAME; | |
4480 | + case 2: | |
4481 | + return V4L2_BUF_FLAG_PFRAME; | |
4482 | + case 3: | |
4483 | + return V4L2_BUF_FLAG_BFRAME; | |
4484 | + default: | |
4485 | + return 0; | |
4486 | + } | |
4487 | + } | |
4488 | + | |
4489 | + return 0; | |
4490 | +} | |
4491 | + | |
4492 | +static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) | |
4493 | +{ | |
4494 | + int sensor_height = 0, sensor_width = 0; | |
4495 | + int width, height, i; | |
4496 | + | |
4497 | + if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | |
4498 | + fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG && | |
4499 | + fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4) | |
4500 | + return -EINVAL; | |
4501 | + | |
4502 | + switch (go->standard) { | |
4503 | + case GO7007_STD_NTSC: | |
4504 | + sensor_width = 720; | |
4505 | + sensor_height = 480; | |
4506 | + break; | |
4507 | + case GO7007_STD_PAL: | |
4508 | + sensor_width = 720; | |
4509 | + sensor_height = 576; | |
4510 | + break; | |
4511 | + case GO7007_STD_OTHER: | |
4512 | + sensor_width = go->board_info->sensor_width; | |
4513 | + sensor_height = go->board_info->sensor_height; | |
4514 | + break; | |
4515 | + } | |
4516 | + | |
4517 | + if (fmt == NULL) { | |
4518 | + width = sensor_width; | |
4519 | + height = sensor_height; | |
4520 | + } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { | |
4521 | + if (fmt->fmt.pix.width > sensor_width) | |
4522 | + width = sensor_width; | |
4523 | + else if (fmt->fmt.pix.width < 144) | |
4524 | + width = 144; | |
4525 | + else | |
4526 | + width = fmt->fmt.pix.width & ~0x0f; | |
4527 | + | |
4528 | + if (fmt->fmt.pix.height > sensor_height) | |
4529 | + height = sensor_height; | |
4530 | + else if (fmt->fmt.pix.height < 96) | |
4531 | + height = 96; | |
4532 | + else | |
4533 | + height = fmt->fmt.pix.height & ~0x0f; | |
4534 | + } else { | |
4535 | + int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height; | |
4536 | + int sensor_size = sensor_width * sensor_height; | |
4537 | + | |
4538 | + if (64 * requested_size < 9 * sensor_size) { | |
4539 | + width = sensor_width / 4; | |
4540 | + height = sensor_height / 4; | |
4541 | + } else if (64 * requested_size < 36 * sensor_size) { | |
4542 | + width = sensor_width / 2; | |
4543 | + height = sensor_height / 2; | |
4544 | + } else { | |
4545 | + width = sensor_width; | |
4546 | + height = sensor_height; | |
4547 | + } | |
4548 | + width &= ~0xf; | |
4549 | + height &= ~0xf; | |
4550 | + } | |
4551 | + | |
4552 | + if (fmt != NULL) { | |
4553 | + u32 pixelformat = fmt->fmt.pix.pixelformat; | |
4554 | + | |
4555 | + memset(fmt, 0, sizeof(*fmt)); | |
4556 | + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4557 | + fmt->fmt.pix.width = width; | |
4558 | + fmt->fmt.pix.height = height; | |
4559 | + fmt->fmt.pix.pixelformat = pixelformat; | |
4560 | + fmt->fmt.pix.field = V4L2_FIELD_NONE; | |
4561 | + fmt->fmt.pix.bytesperline = 0; | |
4562 | + fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; | |
4563 | + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ | |
4564 | + } | |
4565 | + | |
4566 | + if (try) | |
4567 | + return 0; | |
4568 | + | |
4569 | + go->width = width; | |
4570 | + go->height = height; | |
4571 | + go->encoder_h_offset = go->board_info->sensor_h_offset; | |
4572 | + go->encoder_v_offset = go->board_info->sensor_v_offset; | |
4573 | + for (i = 0; i < 4; ++i) | |
4574 | + go->modet[i].enable = 0; | |
4575 | + for (i = 0; i < 1624; ++i) | |
4576 | + go->modet_map[i] = 0; | |
4577 | + | |
4578 | + if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { | |
4579 | + struct video_decoder_resolution res; | |
4580 | + | |
4581 | + res.width = width; | |
4582 | + if (height > sensor_height / 2) { | |
4583 | + res.height = height / 2; | |
4584 | + go->encoder_v_halve = 0; | |
4585 | + } else { | |
4586 | + res.height = height; | |
4587 | + go->encoder_v_halve = 1; | |
4588 | + } | |
4589 | + if (go->i2c_adapter_online) | |
4590 | + i2c_clients_command(&go->i2c_adapter, | |
4591 | + DECODER_SET_RESOLUTION, &res); | |
4592 | + } else { | |
4593 | + if (width <= sensor_width / 4) { | |
4594 | + go->encoder_h_halve = 1; | |
4595 | + go->encoder_v_halve = 1; | |
4596 | + go->encoder_subsample = 1; | |
4597 | + } else if (width <= sensor_width / 2) { | |
4598 | + go->encoder_h_halve = 1; | |
4599 | + go->encoder_v_halve = 1; | |
4600 | + go->encoder_subsample = 0; | |
4601 | + } else { | |
4602 | + go->encoder_h_halve = 0; | |
4603 | + go->encoder_v_halve = 0; | |
4604 | + go->encoder_subsample = 0; | |
4605 | + } | |
4606 | + } | |
4607 | + | |
4608 | + if (fmt == NULL) | |
4609 | + return 0; | |
4610 | + | |
4611 | + switch (fmt->fmt.pix.pixelformat) { | |
4612 | + case V4L2_PIX_FMT_MPEG: | |
4613 | + if (go->format == GO7007_FORMAT_MPEG1 || | |
4614 | + go->format == GO7007_FORMAT_MPEG2 || | |
4615 | + go->format == GO7007_FORMAT_MPEG4) | |
4616 | + break; | |
4617 | + go->format = GO7007_FORMAT_MPEG1; | |
4618 | + go->pali = 0; | |
4619 | + go->aspect_ratio = GO7007_RATIO_1_1; | |
4620 | + go->gop_size = go->sensor_framerate / 1000; | |
4621 | + go->ipb = 0; | |
4622 | + go->closed_gop = 1; | |
4623 | + go->repeat_seqhead = 1; | |
4624 | + go->seq_header_enable = 1; | |
4625 | + go->gop_header_enable = 1; | |
4626 | + go->dvd_mode = 0; | |
4627 | + break; | |
4628 | + /* Backwards compatibility only! */ | |
4629 | + case V4L2_PIX_FMT_MPEG4: | |
4630 | + if (go->format == GO7007_FORMAT_MPEG4) | |
4631 | + break; | |
4632 | + go->format = GO7007_FORMAT_MPEG4; | |
4633 | + go->pali = 0xf5; | |
4634 | + go->aspect_ratio = GO7007_RATIO_1_1; | |
4635 | + go->gop_size = go->sensor_framerate / 1000; | |
4636 | + go->ipb = 0; | |
4637 | + go->closed_gop = 1; | |
4638 | + go->repeat_seqhead = 1; | |
4639 | + go->seq_header_enable = 1; | |
4640 | + go->gop_header_enable = 1; | |
4641 | + go->dvd_mode = 0; | |
4642 | + break; | |
4643 | + case V4L2_PIX_FMT_MJPEG: | |
4644 | + go->format = GO7007_FORMAT_MJPEG; | |
4645 | + go->pali = 0; | |
4646 | + go->aspect_ratio = GO7007_RATIO_1_1; | |
4647 | + go->gop_size = 0; | |
4648 | + go->ipb = 0; | |
4649 | + go->closed_gop = 0; | |
4650 | + go->repeat_seqhead = 0; | |
4651 | + go->seq_header_enable = 0; | |
4652 | + go->gop_header_enable = 0; | |
4653 | + go->dvd_mode = 0; | |
4654 | + break; | |
4655 | + } | |
4656 | + return 0; | |
4657 | +} | |
4658 | + | |
4659 | +static int clip_to_modet_map(struct go7007 *go, int region, | |
4660 | + struct v4l2_clip *clip_list) | |
4661 | +{ | |
4662 | + struct v4l2_clip clip, *clip_ptr; | |
4663 | + int x, y, mbnum; | |
4664 | + | |
4665 | + /* Check if coordinates are OK and if any macroblocks are already | |
4666 | + * used by other regions (besides 0) */ | |
4667 | + clip_ptr = clip_list; | |
4668 | + while (clip_ptr) { | |
4669 | + if (copy_from_user(&clip, clip_ptr, sizeof(clip))) | |
4670 | + return -EFAULT; | |
4671 | + if (clip.c.left < 0 || (clip.c.left & 0xF) || | |
4672 | + clip.c.width <= 0 || (clip.c.width & 0xF)) | |
4673 | + return -EINVAL; | |
4674 | + if (clip.c.left + clip.c.width > go->width) | |
4675 | + return -EINVAL; | |
4676 | + if (clip.c.top < 0 || (clip.c.top & 0xF) || | |
4677 | + clip.c.height <= 0 || (clip.c.height & 0xF)) | |
4678 | + return -EINVAL; | |
4679 | + if (clip.c.top + clip.c.height > go->height) | |
4680 | + return -EINVAL; | |
4681 | + for (y = 0; y < clip.c.height; y += 16) | |
4682 | + for (x = 0; x < clip.c.width; x += 16) { | |
4683 | + mbnum = (go->width >> 4) * | |
4684 | + ((clip.c.top + y) >> 4) + | |
4685 | + ((clip.c.left + x) >> 4); | |
4686 | + if (go->modet_map[mbnum] != 0 && | |
4687 | + go->modet_map[mbnum] != region) | |
4688 | + return -EBUSY; | |
4689 | + } | |
4690 | + clip_ptr = clip.next; | |
4691 | + } | |
4692 | + | |
4693 | + /* Clear old region macroblocks */ | |
4694 | + for (mbnum = 0; mbnum < 1624; ++mbnum) | |
4695 | + if (go->modet_map[mbnum] == region) | |
4696 | + go->modet_map[mbnum] = 0; | |
4697 | + | |
4698 | + /* Claim macroblocks in this list */ | |
4699 | + clip_ptr = clip_list; | |
4700 | + while (clip_ptr) { | |
4701 | + if (copy_from_user(&clip, clip_ptr, sizeof(clip))) | |
4702 | + return -EFAULT; | |
4703 | + for (y = 0; y < clip.c.height; y += 16) | |
4704 | + for (x = 0; x < clip.c.width; x += 16) { | |
4705 | + mbnum = (go->width >> 4) * | |
4706 | + ((clip.c.top + y) >> 4) + | |
4707 | + ((clip.c.left + x) >> 4); | |
4708 | + go->modet_map[mbnum] = region; | |
4709 | + } | |
4710 | + clip_ptr = clip.next; | |
4711 | + } | |
4712 | + return 0; | |
4713 | +} | |
4714 | + | |
4715 | +static int go7007_do_ioctl(struct inode *inode, struct file *file, | |
4716 | + unsigned int cmd, void *arg) | |
4717 | +{ | |
4718 | + struct go7007_file *gofh = file->private_data; | |
4719 | + struct go7007 *go = gofh->go; | |
4720 | + unsigned long flags; | |
4721 | + int retval = 0; | |
4722 | + | |
4723 | + switch (cmd) { | |
4724 | + case VIDIOC_QUERYCAP: | |
4725 | + { | |
4726 | + struct v4l2_capability *cap = arg; | |
4727 | + | |
4728 | + memset(cap, 0, sizeof(*cap)); | |
4729 | + strcpy(cap->driver, "go7007"); | |
4730 | + strncpy(cap->card, go->name, sizeof(cap->card)); | |
4731 | + cap->version = KERNEL_VERSION(0, 9, 8); | |
4732 | + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | |
4733 | + V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */ | |
4734 | + if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) | |
4735 | + cap->capabilities |= V4L2_CAP_TUNER; | |
4736 | + return 0; | |
4737 | + } | |
4738 | + case VIDIOC_ENUM_FMT: | |
4739 | + { | |
4740 | + struct v4l2_fmtdesc *fmt = arg; | |
4741 | + unsigned int index; | |
4742 | + char *desc; | |
4743 | + u32 pixelformat; | |
4744 | + | |
4745 | + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4746 | + return -EINVAL; | |
4747 | + switch (fmt->index) { | |
4748 | + case 0: | |
4749 | + pixelformat = V4L2_PIX_FMT_MJPEG; | |
4750 | + desc = "Motion-JPEG"; | |
4751 | + break; | |
4752 | + case 1: | |
4753 | + pixelformat = V4L2_PIX_FMT_MPEG; | |
4754 | + desc = "MPEG1/MPEG2/MPEG4"; | |
4755 | + break; | |
4756 | + default: | |
4757 | + return -EINVAL; | |
4758 | + } | |
4759 | + index = fmt->index; | |
4760 | + memset(fmt, 0, sizeof(*fmt)); | |
4761 | + fmt->index = index; | |
4762 | + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4763 | + fmt->flags = V4L2_FMT_FLAG_COMPRESSED; | |
4764 | + strncpy(fmt->description, desc, sizeof(fmt->description)); | |
4765 | + fmt->pixelformat = pixelformat; | |
4766 | + | |
4767 | + return 0; | |
4768 | + } | |
4769 | + case VIDIOC_TRY_FMT: | |
4770 | + { | |
4771 | + struct v4l2_format *fmt = arg; | |
4772 | + | |
4773 | + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4774 | + return -EINVAL; | |
4775 | + return set_capture_size(go, fmt, 1); | |
4776 | + } | |
4777 | + case VIDIOC_G_FMT: | |
4778 | + { | |
4779 | + struct v4l2_format *fmt = arg; | |
4780 | + | |
4781 | + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4782 | + return -EINVAL; | |
4783 | + memset(fmt, 0, sizeof(*fmt)); | |
4784 | + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4785 | + fmt->fmt.pix.width = go->width; | |
4786 | + fmt->fmt.pix.height = go->height; | |
4787 | + fmt->fmt.pix.pixelformat = go->format == GO7007_FORMAT_MJPEG ? | |
4788 | + V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG; | |
4789 | + fmt->fmt.pix.field = V4L2_FIELD_NONE; | |
4790 | + fmt->fmt.pix.bytesperline = 0; | |
4791 | + fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; | |
4792 | + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ | |
4793 | + return 0; | |
4794 | + } | |
4795 | + case VIDIOC_S_FMT: | |
4796 | + { | |
4797 | + struct v4l2_format *fmt = arg; | |
4798 | + | |
4799 | + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4800 | + return -EINVAL; | |
4801 | + if (go->streaming) | |
4802 | + return -EBUSY; | |
4803 | + return set_capture_size(go, fmt, 0); | |
4804 | + } | |
4805 | + case VIDIOC_G_FBUF: | |
4806 | + case VIDIOC_S_FBUF: | |
4807 | + return -EINVAL; | |
4808 | + case VIDIOC_REQBUFS: | |
4809 | + { | |
4810 | + struct v4l2_requestbuffers *req = arg; | |
4811 | + unsigned int count, i; | |
4812 | + | |
4813 | + if (go->streaming) | |
4814 | + return -EBUSY; | |
4815 | + if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
4816 | + req->memory != V4L2_MEMORY_MMAP) | |
4817 | + return -EINVAL; | |
4818 | + | |
4819 | + down(&gofh->lock); | |
4820 | + retval = -EBUSY; | |
4821 | + for (i = 0; i < gofh->buf_count; ++i) | |
4822 | + if (gofh->bufs[i].mapped > 0) | |
4823 | + goto unlock_and_return; | |
4824 | + down(&go->hw_lock); | |
4825 | + if (go->in_use > 0 && gofh->buf_count == 0) { | |
4826 | + up(&go->hw_lock); | |
4827 | + goto unlock_and_return; | |
4828 | + } | |
4829 | + if (gofh->buf_count > 0) | |
4830 | + kfree(gofh->bufs); | |
4831 | + retval = -ENOMEM; | |
4832 | + count = req->count; | |
4833 | + if (count > 0) { | |
4834 | + if (count < 2) | |
4835 | + count = 2; | |
4836 | + if (count > 32) | |
4837 | + count = 32; | |
4838 | + gofh->bufs = kmalloc(count * | |
4839 | + sizeof(struct go7007_buffer), | |
4840 | + GFP_KERNEL); | |
4841 | + if (gofh->bufs == NULL) { | |
4842 | + up(&go->hw_lock); | |
4843 | + goto unlock_and_return; | |
4844 | + } | |
4845 | + memset(gofh->bufs, 0, | |
4846 | + count * sizeof(struct go7007_buffer)); | |
4847 | + for (i = 0; i < count; ++i) { | |
4848 | + gofh->bufs[i].go = go; | |
4849 | + gofh->bufs[i].index = i; | |
4850 | + gofh->bufs[i].state = BUF_STATE_IDLE; | |
4851 | + gofh->bufs[i].mapped = 0; | |
4852 | + } | |
4853 | + go->in_use = 1; | |
4854 | + } else { | |
4855 | + go->in_use = 0; | |
4856 | + } | |
4857 | + gofh->buf_count = count; | |
4858 | + up(&go->hw_lock); | |
4859 | + up(&gofh->lock); | |
4860 | + memset(req, 0, sizeof(*req)); | |
4861 | + req->count = count; | |
4862 | + req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4863 | + req->memory = V4L2_MEMORY_MMAP; | |
4864 | + return 0; | |
4865 | + } | |
4866 | + case VIDIOC_QUERYBUF: | |
4867 | + { | |
4868 | + struct v4l2_buffer *buf = arg; | |
4869 | + unsigned int index; | |
4870 | + | |
4871 | + retval = -EINVAL; | |
4872 | + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4873 | + return -EINVAL; | |
4874 | + index = buf->index; | |
4875 | + down(&gofh->lock); | |
4876 | + if (index >= gofh->buf_count) | |
4877 | + goto unlock_and_return; | |
4878 | + memset(buf, 0, sizeof(*buf)); | |
4879 | + buf->index = index; | |
4880 | + buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4881 | + switch (gofh->bufs[index].state) { | |
4882 | + case BUF_STATE_QUEUED: | |
4883 | + buf->flags = V4L2_BUF_FLAG_QUEUED; | |
4884 | + break; | |
4885 | + case BUF_STATE_DONE: | |
4886 | + buf->flags = V4L2_BUF_FLAG_DONE; | |
4887 | + break; | |
4888 | + default: | |
4889 | + buf->flags = 0; | |
4890 | + } | |
4891 | + if (gofh->bufs[index].mapped) | |
4892 | + buf->flags |= V4L2_BUF_FLAG_MAPPED; | |
4893 | + buf->memory = V4L2_MEMORY_MMAP; | |
4894 | + buf->m.offset = index * GO7007_BUF_SIZE; | |
4895 | + buf->length = GO7007_BUF_SIZE; | |
4896 | + up(&gofh->lock); | |
4897 | + | |
4898 | + return 0; | |
4899 | + } | |
4900 | + case VIDIOC_QBUF: | |
4901 | + { | |
4902 | + struct v4l2_buffer *buf = arg; | |
4903 | + struct go7007_buffer *gobuf; | |
4904 | + int ret; | |
4905 | + | |
4906 | + retval = -EINVAL; | |
4907 | + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
4908 | + buf->memory != V4L2_MEMORY_MMAP) | |
4909 | + return -EINVAL; | |
4910 | + down(&gofh->lock); | |
4911 | + if (buf->index < 0 || buf->index >= gofh->buf_count) | |
4912 | + goto unlock_and_return; | |
4913 | + gobuf = &gofh->bufs[buf->index]; | |
4914 | + if (gobuf->mapped == 0) | |
4915 | + goto unlock_and_return; | |
4916 | + retval = -EBUSY; | |
4917 | + if (gobuf->state != BUF_STATE_IDLE) | |
4918 | + goto unlock_and_return; | |
4919 | + /* offset will be 0 until we really support USERPTR streaming */ | |
4920 | + gobuf->offset = gobuf->user_addr & ~PAGE_MASK; | |
4921 | + gobuf->bytesused = 0; | |
4922 | + gobuf->frame_offset = 0; | |
4923 | + gobuf->modet_active = 0; | |
4924 | + if (gobuf->offset > 0) | |
4925 | + gobuf->page_count = GO7007_BUF_PAGES + 1; | |
4926 | + else | |
4927 | + gobuf->page_count = GO7007_BUF_PAGES; | |
4928 | + retval = -ENOMEM; | |
4929 | + down_read(¤t->mm->mmap_sem); | |
4930 | + ret = get_user_pages(current, current->mm, | |
4931 | + gobuf->user_addr & PAGE_MASK, gobuf->page_count, | |
4932 | + 1, 1, gobuf->pages, NULL); | |
4933 | + up_read(¤t->mm->mmap_sem); | |
4934 | + if (ret != gobuf->page_count) { | |
4935 | + int i; | |
4936 | + for (i = 0; i < ret; ++i) | |
4937 | + page_cache_release(gobuf->pages[i]); | |
4938 | + gobuf->page_count = 0; | |
4939 | + goto unlock_and_return; | |
4940 | + } | |
4941 | + gobuf->state = BUF_STATE_QUEUED; | |
4942 | + spin_lock_irqsave(&go->spinlock, flags); | |
4943 | + list_add_tail(&gobuf->stream, &go->stream); | |
4944 | + spin_unlock_irqrestore(&go->spinlock, flags); | |
4945 | + up(&gofh->lock); | |
4946 | + return 0; | |
4947 | + } | |
4948 | + case VIDIOC_DQBUF: | |
4949 | + { | |
4950 | + struct v4l2_buffer *buf = arg; | |
4951 | + struct go7007_buffer *gobuf; | |
4952 | + u32 frame_type_flag; | |
4953 | + DEFINE_WAIT(wait); | |
4954 | + | |
4955 | + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
4956 | + return -EINVAL; | |
4957 | + if (buf->memory != V4L2_MEMORY_MMAP) | |
4958 | + return -EINVAL; | |
4959 | + down(&gofh->lock); | |
4960 | + retval = -EINVAL; | |
4961 | + if (list_empty(&go->stream)) | |
4962 | + goto unlock_and_return; | |
4963 | + gobuf = list_entry(go->stream.next, | |
4964 | + struct go7007_buffer, stream); | |
4965 | + retval = -EAGAIN; | |
4966 | + if (gobuf->state != BUF_STATE_DONE && | |
4967 | + !(file->f_flags & O_NONBLOCK)) { | |
4968 | + for (;;) { | |
4969 | + prepare_to_wait(&go->frame_waitq, &wait, | |
4970 | + TASK_INTERRUPTIBLE); | |
4971 | + if (gobuf->state == BUF_STATE_DONE) | |
4972 | + break; | |
4973 | + if (signal_pending(current)) { | |
4974 | + retval = -ERESTARTSYS; | |
4975 | + break; | |
4976 | + } | |
4977 | + schedule(); | |
4978 | + } | |
4979 | + finish_wait(&go->frame_waitq, &wait); | |
4980 | + } | |
4981 | + if (gobuf->state != BUF_STATE_DONE) | |
4982 | + goto unlock_and_return; | |
4983 | + spin_lock_irqsave(&go->spinlock, flags); | |
4984 | + deactivate_buffer(gobuf); | |
4985 | + spin_unlock_irqrestore(&go->spinlock, flags); | |
4986 | + frame_type_flag = get_frame_type_flag(gobuf, go->format); | |
4987 | + gobuf->state = BUF_STATE_IDLE; | |
4988 | + memset(buf, 0, sizeof(*buf)); | |
4989 | + buf->index = gobuf->index; | |
4990 | + buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
4991 | + buf->bytesused = gobuf->bytesused; | |
4992 | + buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag; | |
4993 | + buf->field = V4L2_FIELD_NONE; | |
4994 | + buf->timestamp = gobuf->timestamp; | |
4995 | + buf->sequence = gobuf->seq; | |
4996 | + buf->memory = V4L2_MEMORY_MMAP; | |
4997 | + buf->m.offset = gobuf->index * GO7007_BUF_SIZE; | |
4998 | + buf->length = GO7007_BUF_SIZE; | |
4999 | + buf->reserved = gobuf->modet_active; | |
5000 | + up(&gofh->lock); | |
5001 | + return 0; | |
5002 | + } | |
5003 | + case VIDIOC_STREAMON: | |
5004 | + { | |
5005 | + unsigned int *type = arg; | |
5006 | + | |
5007 | + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5008 | + return -EINVAL; | |
5009 | + down(&gofh->lock); | |
5010 | + down(&go->hw_lock); | |
5011 | + if (!go->streaming) { | |
5012 | + go->streaming = 1; | |
5013 | + go->next_seq = 0; | |
5014 | + go->active_buf = NULL; | |
5015 | + if (go7007_start_encoder(go) < 0) | |
5016 | + retval = -EIO; | |
5017 | + else | |
5018 | + retval = 0; | |
5019 | + } | |
5020 | + up(&go->hw_lock); | |
5021 | + up(&gofh->lock); | |
5022 | + return retval; | |
5023 | + } | |
5024 | + case VIDIOC_STREAMOFF: | |
5025 | + { | |
5026 | + unsigned int *type = arg; | |
5027 | + | |
5028 | + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5029 | + return -EINVAL; | |
5030 | + down(&gofh->lock); | |
5031 | + go7007_streamoff(go); | |
5032 | + up(&gofh->lock); | |
5033 | + return 0; | |
5034 | + } | |
5035 | + case VIDIOC_QUERYCTRL: | |
5036 | + { | |
5037 | + struct v4l2_queryctrl *ctrl = arg; | |
5038 | + u32 id; | |
5039 | + | |
5040 | + if (!go->i2c_adapter_online) | |
5041 | + return -EIO; | |
5042 | + id = ctrl->id; | |
5043 | + memset(ctrl, 0, sizeof(*ctrl)); | |
5044 | + ctrl->id = id; | |
5045 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, arg); | |
5046 | + return ctrl->name[0] == 0 ? -EINVAL : 0; | |
5047 | + } | |
5048 | + case VIDIOC_G_CTRL: | |
5049 | + { | |
5050 | + struct v4l2_control *ctrl = arg; | |
5051 | + struct v4l2_queryctrl query; | |
5052 | + | |
5053 | + if (!go->i2c_adapter_online) | |
5054 | + return -EIO; | |
5055 | + memset(&query, 0, sizeof(query)); | |
5056 | + query.id = ctrl->id; | |
5057 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query); | |
5058 | + if (query.name[0] == 0) | |
5059 | + return -EINVAL; | |
5060 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg); | |
5061 | + return 0; | |
5062 | + } | |
5063 | + case VIDIOC_S_CTRL: | |
5064 | + { | |
5065 | + struct v4l2_control *ctrl = arg; | |
5066 | + struct v4l2_queryctrl query; | |
5067 | + | |
5068 | + if (!go->i2c_adapter_online) | |
5069 | + return -EIO; | |
5070 | + memset(&query, 0, sizeof(query)); | |
5071 | + query.id = ctrl->id; | |
5072 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query); | |
5073 | + if (query.name[0] == 0) | |
5074 | + return -EINVAL; | |
5075 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg); | |
5076 | + return 0; | |
5077 | + } | |
5078 | + case VIDIOC_G_PARM: | |
5079 | + { | |
5080 | + struct v4l2_streamparm *parm = arg; | |
5081 | + struct v4l2_fract timeperframe = { | |
5082 | + .numerator = 1001 * go->fps_scale, | |
5083 | + .denominator = go->sensor_framerate, | |
5084 | + }; | |
5085 | + | |
5086 | + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5087 | + return -EINVAL; | |
5088 | + memset(parm, 0, sizeof(*parm)); | |
5089 | + parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
5090 | + parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; | |
5091 | + parm->parm.capture.timeperframe = timeperframe; | |
5092 | + return 0; | |
5093 | + } | |
5094 | + case VIDIOC_S_PARM: | |
5095 | + { | |
5096 | + struct v4l2_streamparm *parm = arg; | |
5097 | + unsigned int n, d; | |
5098 | + | |
5099 | + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5100 | + return -EINVAL; | |
5101 | + if (parm->parm.capture.capturemode != 0) | |
5102 | + return -EINVAL; | |
5103 | + n = go->sensor_framerate * | |
5104 | + parm->parm.capture.timeperframe.numerator; | |
5105 | + d = 1001 * parm->parm.capture.timeperframe.denominator; | |
5106 | + if (n != 0 && d != 0 && n > d) | |
5107 | + go->fps_scale = (n + d/2) / d; | |
5108 | + else | |
5109 | + go->fps_scale = 1; | |
5110 | + return 0; | |
5111 | + } | |
5112 | + case VIDIOC_ENUMSTD: | |
5113 | + { | |
5114 | + struct v4l2_standard *std = arg; | |
5115 | + | |
5116 | + if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | |
5117 | + go->input == go->board_info->num_inputs - 1) { | |
5118 | + if (!go->i2c_adapter_online) | |
5119 | + return -EIO; | |
5120 | + i2c_clients_command(&go->i2c_adapter, | |
5121 | + VIDIOC_ENUMSTD, arg); | |
5122 | + if (!std->id) /* hack to indicate EINVAL from tuner */ | |
5123 | + return -EINVAL; | |
5124 | + } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { | |
5125 | + switch (std->index) { | |
5126 | + case 0: | |
5127 | + v4l2_video_std_construct(std, | |
5128 | + V4L2_STD_NTSC, "NTSC"); | |
5129 | + break; | |
5130 | + case 1: | |
5131 | + v4l2_video_std_construct(std, | |
5132 | + V4L2_STD_PAL | V4L2_STD_SECAM, | |
5133 | + "PAL/SECAM"); | |
5134 | + break; | |
5135 | + default: | |
5136 | + return -EINVAL; | |
5137 | + } | |
5138 | + } else { | |
5139 | + if (std->index != 0) | |
5140 | + return -EINVAL; | |
5141 | + memset(std, 0, sizeof(*std)); | |
5142 | + snprintf(std->name, sizeof(std->name), "%dx%d, %dfps", | |
5143 | + go->board_info->sensor_width, | |
5144 | + go->board_info->sensor_height, | |
5145 | + go->board_info->sensor_framerate / 1000); | |
5146 | + std->frameperiod.numerator = 1001; | |
5147 | + std->frameperiod.denominator = | |
5148 | + go->board_info->sensor_framerate; | |
5149 | + } | |
5150 | + return 0; | |
5151 | + } | |
5152 | + case VIDIOC_G_STD: | |
5153 | + { | |
5154 | + v4l2_std_id *std = arg; | |
5155 | + | |
5156 | + if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | |
5157 | + go->input == go->board_info->num_inputs - 1) { | |
5158 | + if (!go->i2c_adapter_online) | |
5159 | + return -EIO; | |
5160 | + i2c_clients_command(&go->i2c_adapter, | |
5161 | + VIDIOC_G_STD, arg); | |
5162 | + } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { | |
5163 | + if (go->standard == GO7007_STD_NTSC) | |
5164 | + *std = V4L2_STD_NTSC; | |
5165 | + else | |
5166 | + *std = V4L2_STD_PAL | V4L2_STD_SECAM; | |
5167 | + } else | |
5168 | + *std = 0; | |
5169 | + return 0; | |
5170 | + } | |
5171 | + case VIDIOC_S_STD: | |
5172 | + { | |
5173 | + v4l2_std_id *std = arg; | |
5174 | + int norm; | |
5175 | + | |
5176 | + if (go->streaming) | |
5177 | + return -EBUSY; | |
5178 | + if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && | |
5179 | + *std != 0) | |
5180 | + return -EINVAL; | |
5181 | + if (*std == 0) | |
5182 | + return -EINVAL; | |
5183 | + if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | |
5184 | + go->input == go->board_info->num_inputs - 1) { | |
5185 | + if (!go->i2c_adapter_online) | |
5186 | + return -EIO; | |
5187 | + i2c_clients_command(&go->i2c_adapter, | |
5188 | + VIDIOC_S_STD, arg); | |
5189 | + if (!*std) /* hack to indicate EINVAL from tuner */ | |
5190 | + return -EINVAL; | |
5191 | + } | |
5192 | + if (*std & V4L2_STD_NTSC) { | |
5193 | + go->standard = GO7007_STD_NTSC; | |
5194 | + go->sensor_framerate = 30000; | |
5195 | + norm = VIDEO_MODE_NTSC; | |
5196 | + } else if (*std & V4L2_STD_PAL) { | |
5197 | + go->standard = GO7007_STD_PAL; | |
5198 | + go->sensor_framerate = 25025; | |
5199 | + norm = VIDEO_MODE_PAL; | |
5200 | + } else if (*std & V4L2_STD_SECAM) { | |
5201 | + go->standard = GO7007_STD_PAL; | |
5202 | + go->sensor_framerate = 25025; | |
5203 | + norm = VIDEO_MODE_SECAM; | |
5204 | + } else | |
5205 | + return -EINVAL; | |
5206 | + if (go->i2c_adapter_online) | |
5207 | + i2c_clients_command(&go->i2c_adapter, | |
5208 | + DECODER_SET_NORM, &norm); | |
5209 | + set_capture_size(go, NULL, 0); | |
5210 | + return 0; | |
5211 | + } | |
5212 | + case VIDIOC_QUERYSTD: | |
5213 | + { | |
5214 | + v4l2_std_id *std = arg; | |
5215 | + | |
5216 | + if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | |
5217 | + go->input == go->board_info->num_inputs - 1) { | |
5218 | + if (!go->i2c_adapter_online) | |
5219 | + return -EIO; | |
5220 | + i2c_clients_command(&go->i2c_adapter, | |
5221 | + VIDIOC_QUERYSTD, arg); | |
5222 | + } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) | |
5223 | + *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; | |
5224 | + else | |
5225 | + *std = 0; | |
5226 | + return 0; | |
5227 | + } | |
5228 | + case VIDIOC_ENUMINPUT: | |
5229 | + { | |
5230 | + struct v4l2_input *inp = arg; | |
5231 | + int index; | |
5232 | + | |
5233 | + if (inp->index >= go->board_info->num_inputs) | |
5234 | + return -EINVAL; | |
5235 | + index = inp->index; | |
5236 | + memset(inp, 0, sizeof(*inp)); | |
5237 | + inp->index = index; | |
5238 | + strncpy(inp->name, go->board_info->inputs[index].name, | |
5239 | + sizeof(inp->name)); | |
5240 | + /* If this board has a tuner, it will be the last input */ | |
5241 | + if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | |
5242 | + index == go->board_info->num_inputs - 1) | |
5243 | + inp->type = V4L2_INPUT_TYPE_TUNER; | |
5244 | + else | |
5245 | + inp->type = V4L2_INPUT_TYPE_CAMERA; | |
5246 | + inp->audioset = 0; | |
5247 | + inp->tuner = 0; | |
5248 | + if (go->board_info->sensor_flags & GO7007_SENSOR_TV) | |
5249 | + inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | | |
5250 | + V4L2_STD_SECAM; | |
5251 | + else | |
5252 | + inp->std = 0; | |
5253 | + return 0; | |
5254 | + } | |
5255 | + case VIDIOC_G_INPUT: | |
5256 | + { | |
5257 | + int *input = arg; | |
5258 | + | |
5259 | + *input = go->input; | |
5260 | + return 0; | |
5261 | + } | |
5262 | + case VIDIOC_S_INPUT: | |
5263 | + { | |
5264 | + int *input = arg; | |
5265 | + | |
5266 | + if (*input >= go->board_info->num_inputs) | |
5267 | + return -EINVAL; | |
5268 | + if (go->streaming) | |
5269 | + return -EBUSY; | |
5270 | + go->input = *input; | |
5271 | + if (go->i2c_adapter_online) { | |
5272 | + i2c_clients_command(&go->i2c_adapter, DECODER_SET_INPUT, | |
5273 | + &go->board_info->inputs[*input].video_input); | |
5274 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO, | |
5275 | + &go->board_info->inputs[*input].audio_input); | |
5276 | + } | |
5277 | + return 0; | |
5278 | + } | |
5279 | + case VIDIOC_G_TUNER: | |
5280 | + { | |
5281 | + struct v4l2_tuner *t = arg; | |
5282 | + | |
5283 | + if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | |
5284 | + return -EINVAL; | |
5285 | + if (t->index != 0) | |
5286 | + return -EINVAL; | |
5287 | + if (!go->i2c_adapter_online) | |
5288 | + return -EIO; | |
5289 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, arg); | |
5290 | + t->index = 0; | |
5291 | + return 0; | |
5292 | + } | |
5293 | + case VIDIOC_S_TUNER: | |
5294 | + { | |
5295 | + struct v4l2_tuner *t = arg; | |
5296 | + | |
5297 | + if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | |
5298 | + return -EINVAL; | |
5299 | + if (t->index != 0) | |
5300 | + return -EINVAL; | |
5301 | + if (!go->i2c_adapter_online) | |
5302 | + return -EIO; | |
5303 | + switch (go->board_id) { | |
5304 | + case GO7007_BOARDID_PX_TV402U_NA: | |
5305 | + case GO7007_BOARDID_PX_TV402U_JP: | |
5306 | + /* No selectable options currently */ | |
5307 | + if (t->audmode != V4L2_TUNER_MODE_STEREO) | |
5308 | + return -EINVAL; | |
5309 | + break; | |
5310 | + } | |
5311 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, arg); | |
5312 | + return 0; | |
5313 | + } | |
5314 | + case VIDIOC_G_FREQUENCY: | |
5315 | + { | |
5316 | + struct v4l2_frequency *f = arg; | |
5317 | + | |
5318 | + if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | |
5319 | + return -EINVAL; | |
5320 | + if (!go->i2c_adapter_online) | |
5321 | + return -EIO; | |
5322 | + memset(f, 0, sizeof(*f)); | |
5323 | + f->type = V4L2_TUNER_ANALOG_TV; | |
5324 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, arg); | |
5325 | + return 0; | |
5326 | + } | |
5327 | + case VIDIOC_S_FREQUENCY: | |
5328 | + { | |
5329 | + if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | |
5330 | + return -EINVAL; | |
5331 | + if (!go->i2c_adapter_online) | |
5332 | + return -EIO; | |
5333 | + i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, arg); | |
5334 | + return 0; | |
5335 | + } | |
5336 | + case VIDIOC_CROPCAP: | |
5337 | + { | |
5338 | + struct v4l2_cropcap *cropcap = arg; | |
5339 | + | |
5340 | + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5341 | + return -EINVAL; | |
5342 | + memset(cropcap, 0, sizeof(*cropcap)); | |
5343 | + cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
5344 | + /* These specify the raw input of the sensor */ | |
5345 | + switch (go->standard) { | |
5346 | + case GO7007_STD_NTSC: | |
5347 | + cropcap->bounds.top = 0; | |
5348 | + cropcap->bounds.left = 0; | |
5349 | + cropcap->bounds.width = 720; | |
5350 | + cropcap->bounds.height = 480; | |
5351 | + cropcap->defrect.top = 0; | |
5352 | + cropcap->defrect.left = 0; | |
5353 | + cropcap->defrect.width = 720; | |
5354 | + cropcap->defrect.height = 480; | |
5355 | + break; | |
5356 | + case GO7007_STD_PAL: | |
5357 | + cropcap->bounds.top = 0; | |
5358 | + cropcap->bounds.left = 0; | |
5359 | + cropcap->bounds.width = 720; | |
5360 | + cropcap->bounds.height = 576; | |
5361 | + cropcap->defrect.top = 0; | |
5362 | + cropcap->defrect.left = 0; | |
5363 | + cropcap->defrect.width = 720; | |
5364 | + cropcap->defrect.height = 576; | |
5365 | + break; | |
5366 | + case GO7007_STD_OTHER: | |
5367 | + cropcap->bounds.top = 0; | |
5368 | + cropcap->bounds.left = 0; | |
5369 | + cropcap->bounds.width = go->board_info->sensor_width; | |
5370 | + cropcap->bounds.height = go->board_info->sensor_height; | |
5371 | + cropcap->defrect.top = 0; | |
5372 | + cropcap->defrect.left = 0; | |
5373 | + cropcap->defrect.width = go->board_info->sensor_width; | |
5374 | + cropcap->defrect.height = go->board_info->sensor_height; | |
5375 | + break; | |
5376 | + } | |
5377 | + | |
5378 | + return 0; | |
5379 | + } | |
5380 | + case VIDIOC_G_CROP: | |
5381 | + { | |
5382 | + struct v4l2_crop *crop = arg; | |
5383 | + | |
5384 | + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5385 | + return -EINVAL; | |
5386 | + memset(crop, 0, sizeof(*crop)); | |
5387 | + crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
5388 | + /* These specify the raw input of the sensor */ | |
5389 | + switch (go->standard) { | |
5390 | + case GO7007_STD_NTSC: | |
5391 | + crop->c.top = 0; | |
5392 | + crop->c.left = 0; | |
5393 | + crop->c.width = 720; | |
5394 | + crop->c.height = 480; | |
5395 | + break; | |
5396 | + case GO7007_STD_PAL: | |
5397 | + crop->c.top = 0; | |
5398 | + crop->c.left = 0; | |
5399 | + crop->c.width = 720; | |
5400 | + crop->c.height = 576; | |
5401 | + break; | |
5402 | + case GO7007_STD_OTHER: | |
5403 | + crop->c.top = 0; | |
5404 | + crop->c.left = 0; | |
5405 | + crop->c.width = go->board_info->sensor_width; | |
5406 | + crop->c.height = go->board_info->sensor_height; | |
5407 | + break; | |
5408 | + } | |
5409 | + | |
5410 | + return 0; | |
5411 | + } | |
5412 | + case VIDIOC_S_CROP: | |
5413 | + { | |
5414 | + struct v4l2_crop *crop = arg; | |
5415 | + | |
5416 | + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
5417 | + return -EINVAL; | |
5418 | + return 0; | |
5419 | + } | |
5420 | + case VIDIOC_G_JPEGCOMP: | |
5421 | + { | |
5422 | + struct v4l2_jpegcompression *params = arg; | |
5423 | + | |
5424 | + memset(params, 0, sizeof(*params)); | |
5425 | + params->quality = 50; /* ?? */ | |
5426 | + params->jpeg_markers = V4L2_JPEG_MARKER_DHT | | |
5427 | + V4L2_JPEG_MARKER_DQT; | |
5428 | + | |
5429 | + return 0; | |
5430 | + } | |
5431 | + case VIDIOC_S_JPEGCOMP: | |
5432 | + { | |
5433 | + struct v4l2_jpegcompression *params = arg; | |
5434 | + | |
5435 | + if (params->quality != 50 || | |
5436 | + params->jpeg_markers != (V4L2_JPEG_MARKER_DHT | | |
5437 | + V4L2_JPEG_MARKER_DQT)) | |
5438 | + return -EINVAL; | |
5439 | + return 0; | |
5440 | + } | |
5441 | + /* Temporary ioctls for controlling compression characteristics */ | |
5442 | + case GO7007IOC_S_BITRATE: | |
5443 | + { | |
5444 | + int *bitrate = arg; | |
5445 | + | |
5446 | + if (go->streaming) | |
5447 | + return -EINVAL; | |
5448 | + /* Upper bound is kind of arbitrary here */ | |
5449 | + if (*bitrate < 64000 || *bitrate > 10000000) | |
5450 | + return -EINVAL; | |
5451 | + go->bitrate = *bitrate; | |
5452 | + return 0; | |
5453 | + } | |
5454 | + case GO7007IOC_G_BITRATE: | |
5455 | + { | |
5456 | + int *bitrate = arg; | |
5457 | + | |
5458 | + *bitrate = go->bitrate; | |
5459 | + return 0; | |
5460 | + } | |
5461 | + case GO7007IOC_S_COMP_PARAMS: | |
5462 | + { | |
5463 | + struct go7007_comp_params *comp = arg; | |
5464 | + | |
5465 | + if (go->format == GO7007_FORMAT_MJPEG) | |
5466 | + return -EINVAL; | |
5467 | + if (comp->gop_size > 0) | |
5468 | + go->gop_size = comp->gop_size; | |
5469 | + else | |
5470 | + go->gop_size = go->sensor_framerate / 1000; | |
5471 | + if (go->gop_size != 15) | |
5472 | + go->dvd_mode = 0; | |
5473 | + /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */ | |
5474 | + if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { | |
5475 | + switch (comp->aspect_ratio) { | |
5476 | + case GO7007_ASPECT_RATIO_4_3_NTSC: | |
5477 | + case GO7007_ASPECT_RATIO_4_3_PAL: | |
5478 | + go->aspect_ratio = GO7007_RATIO_4_3; | |
5479 | + break; | |
5480 | + case GO7007_ASPECT_RATIO_16_9_NTSC: | |
5481 | + case GO7007_ASPECT_RATIO_16_9_PAL: | |
5482 | + go->aspect_ratio = GO7007_RATIO_16_9; | |
5483 | + break; | |
5484 | + default: | |
5485 | + go->aspect_ratio = GO7007_RATIO_1_1; | |
5486 | + break; | |
5487 | + } | |
5488 | + } | |
5489 | + if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) { | |
5490 | + go->dvd_mode = 0; | |
5491 | + go->seq_header_enable = 0; | |
5492 | + } else { | |
5493 | + go->seq_header_enable = 1; | |
5494 | + } | |
5495 | + /* fall-through */ | |
5496 | + } | |
5497 | + case GO7007IOC_G_COMP_PARAMS: | |
5498 | + { | |
5499 | + struct go7007_comp_params *comp = arg; | |
5500 | + | |
5501 | + if (go->format == GO7007_FORMAT_MJPEG) | |
5502 | + return -EINVAL; | |
5503 | + memset(comp, 0, sizeof(*comp)); | |
5504 | + comp->gop_size = go->gop_size; | |
5505 | + comp->max_b_frames = go->ipb ? 2 : 0; | |
5506 | + switch (go->aspect_ratio) { | |
5507 | + case GO7007_RATIO_4_3: | |
5508 | + if (go->standard == GO7007_STD_NTSC) | |
5509 | + comp->aspect_ratio = | |
5510 | + GO7007_ASPECT_RATIO_4_3_NTSC; | |
5511 | + else | |
5512 | + comp->aspect_ratio = | |
5513 | + GO7007_ASPECT_RATIO_4_3_PAL; | |
5514 | + break; | |
5515 | + case GO7007_RATIO_16_9: | |
5516 | + if (go->standard == GO7007_STD_NTSC) | |
5517 | + comp->aspect_ratio = | |
5518 | + GO7007_ASPECT_RATIO_16_9_NTSC; | |
5519 | + else | |
5520 | + comp->aspect_ratio = | |
5521 | + GO7007_ASPECT_RATIO_16_9_PAL; | |
5522 | + break; | |
5523 | + default: | |
5524 | + comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1; | |
5525 | + break; | |
5526 | + } | |
5527 | + if (go->closed_gop) | |
5528 | + comp->flags |= GO7007_COMP_CLOSED_GOP; | |
5529 | + if (!go->seq_header_enable) | |
5530 | + comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER; | |
5531 | + return 0; | |
5532 | + } | |
5533 | + case GO7007IOC_S_MPEG_PARAMS: | |
5534 | + { | |
5535 | + struct go7007_mpeg_params *mpeg = arg; | |
5536 | + | |
5537 | + if (go->format != GO7007_FORMAT_MPEG1 && | |
5538 | + go->format != GO7007_FORMAT_MPEG2 && | |
5539 | + go->format != GO7007_FORMAT_MPEG4) | |
5540 | + return -EINVAL; | |
5541 | + | |
5542 | + if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) { | |
5543 | + go->format = GO7007_FORMAT_MPEG2; | |
5544 | + go->bitrate = 9800000; | |
5545 | + go->gop_size = 15; | |
5546 | + go->pali = 0x48; | |
5547 | + go->closed_gop = 1; | |
5548 | + go->repeat_seqhead = 0; | |
5549 | + go->seq_header_enable = 1; | |
5550 | + go->gop_header_enable = 1; | |
5551 | + go->dvd_mode = 1; | |
5552 | + } else { | |
5553 | + switch (mpeg->mpeg_video_standard) { | |
5554 | + case GO7007_MPEG_VIDEO_MPEG1: | |
5555 | + go->format = GO7007_FORMAT_MPEG1; | |
5556 | + go->pali = 0; | |
5557 | + break; | |
5558 | + case GO7007_MPEG_VIDEO_MPEG2: | |
5559 | + go->format = GO7007_FORMAT_MPEG2; | |
5560 | + if (mpeg->pali >> 24 == 2) | |
5561 | + go->pali = mpeg->pali & 0xff; | |
5562 | + else | |
5563 | + go->pali = 0x48; | |
5564 | + break; | |
5565 | + case GO7007_MPEG_VIDEO_MPEG4: | |
5566 | + go->format = GO7007_FORMAT_MPEG4; | |
5567 | + if (mpeg->pali >> 24 == 4) | |
5568 | + go->pali = mpeg->pali & 0xff; | |
5569 | + else | |
5570 | + go->pali = 0xf5; | |
5571 | + break; | |
5572 | + default: | |
5573 | + return -EINVAL; | |
5574 | + } | |
5575 | + go->gop_header_enable = | |
5576 | + mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER | |
5577 | + ? 0 : 1; | |
5578 | + if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) | |
5579 | + go->repeat_seqhead = 1; | |
5580 | + else | |
5581 | + go->repeat_seqhead = 0; | |
5582 | + go->dvd_mode = 0; | |
5583 | + } | |
5584 | + /* fall-through */ | |
5585 | + } | |
5586 | + case GO7007IOC_G_MPEG_PARAMS: | |
5587 | + { | |
5588 | + struct go7007_mpeg_params *mpeg = arg; | |
5589 | + | |
5590 | + memset(mpeg, 0, sizeof(*mpeg)); | |
5591 | + switch (go->format) { | |
5592 | + case GO7007_FORMAT_MPEG1: | |
5593 | + mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1; | |
5594 | + mpeg->pali = 0; | |
5595 | + break; | |
5596 | + case GO7007_FORMAT_MPEG2: | |
5597 | + mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2; | |
5598 | + mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali); | |
5599 | + break; | |
5600 | + case GO7007_FORMAT_MPEG4: | |
5601 | + mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4; | |
5602 | + mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali); | |
5603 | + break; | |
5604 | + default: | |
5605 | + return -EINVAL; | |
5606 | + } | |
5607 | + if (!go->gop_header_enable) | |
5608 | + mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER; | |
5609 | + if (go->repeat_seqhead) | |
5610 | + mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER; | |
5611 | + if (go->dvd_mode) | |
5612 | + mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE; | |
5613 | + return 0; | |
5614 | + } | |
5615 | + case GO7007IOC_S_MD_PARAMS: | |
5616 | + { | |
5617 | + struct go7007_md_params *mdp = arg; | |
5618 | + | |
5619 | + if (mdp->region > 3) | |
5620 | + return -EINVAL; | |
5621 | + if (mdp->trigger > 0) { | |
5622 | + go->modet[mdp->region].pixel_threshold = | |
5623 | + mdp->pixel_threshold >> 1; | |
5624 | + go->modet[mdp->region].motion_threshold = | |
5625 | + mdp->motion_threshold >> 1; | |
5626 | + go->modet[mdp->region].mb_threshold = | |
5627 | + mdp->trigger >> 1; | |
5628 | + go->modet[mdp->region].enable = 1; | |
5629 | + } else | |
5630 | + go->modet[mdp->region].enable = 0; | |
5631 | + /* fall-through */ | |
5632 | + } | |
5633 | + case GO7007IOC_G_MD_PARAMS: | |
5634 | + { | |
5635 | + struct go7007_md_params *mdp = arg; | |
5636 | + int region = mdp->region; | |
5637 | + | |
5638 | + if (mdp->region > 3) | |
5639 | + return -EINVAL; | |
5640 | + memset(mdp, 0, sizeof(struct go7007_md_params)); | |
5641 | + mdp->region = region; | |
5642 | + if (!go->modet[region].enable) | |
5643 | + return 0; | |
5644 | + mdp->pixel_threshold = | |
5645 | + (go->modet[region].pixel_threshold << 1) + 1; | |
5646 | + mdp->motion_threshold = | |
5647 | + (go->modet[region].motion_threshold << 1) + 1; | |
5648 | + mdp->trigger = | |
5649 | + (go->modet[region].mb_threshold << 1) + 1; | |
5650 | + return 0; | |
5651 | + } | |
5652 | + case GO7007IOC_S_MD_REGION: | |
5653 | + { | |
5654 | + struct go7007_md_region *region = arg; | |
5655 | + | |
5656 | + if (region->region < 1 || region->region > 3) | |
5657 | + return -EINVAL; | |
5658 | + return clip_to_modet_map(go, region->region, region->clips); | |
5659 | + } | |
5660 | + default: | |
5661 | + printk(KERN_DEBUG "go7007: unsupported ioctl %d\n", cmd); | |
5662 | + return -ENOIOCTLCMD; | |
5663 | + } | |
5664 | + return 0; | |
5665 | + | |
5666 | +unlock_and_return: | |
5667 | + up(&gofh->lock); | |
5668 | + return retval; | |
5669 | +} | |
5670 | + | |
5671 | +static int go7007_ioctl(struct inode *inode, struct file *file, | |
5672 | + unsigned int cmd, unsigned long arg) | |
5673 | +{ | |
5674 | + struct go7007_file *gofh = file->private_data; | |
5675 | + | |
5676 | + if (gofh->go->status != STATUS_ONLINE) | |
5677 | + return -EIO; | |
5678 | + | |
5679 | + return video_usercopy(inode, file, cmd, arg, go7007_do_ioctl); | |
5680 | +} | |
5681 | + | |
5682 | +static ssize_t go7007_read(struct file *file, char __user *data, | |
5683 | + size_t count, loff_t *ppos) | |
5684 | +{ | |
5685 | + return -EINVAL; | |
5686 | +} | |
5687 | + | |
5688 | +static void go7007_vm_open(struct vm_area_struct *vma) | |
5689 | +{ | |
5690 | + struct go7007_buffer *gobuf = vma->vm_private_data; | |
5691 | + | |
5692 | + ++gobuf->mapped; | |
5693 | +} | |
5694 | + | |
5695 | +static void go7007_vm_close(struct vm_area_struct *vma) | |
5696 | +{ | |
5697 | + struct go7007_buffer *gobuf = vma->vm_private_data; | |
5698 | + unsigned long flags; | |
5699 | + | |
5700 | + if (--gobuf->mapped == 0) { | |
5701 | + spin_lock_irqsave(&gobuf->go->spinlock, flags); | |
5702 | + deactivate_buffer(gobuf); | |
5703 | + spin_unlock_irqrestore(&gobuf->go->spinlock, flags); | |
5704 | + } | |
5705 | +} | |
5706 | + | |
5707 | +/* Copied from videobuf-dma-sg.c */ | |
5708 | +static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |
5709 | +{ | |
5710 | + struct page *page; | |
5711 | + | |
5712 | + page = alloc_page(GFP_USER | __GFP_DMA32); | |
5713 | + if (!page) | |
5714 | + return VM_FAULT_OOM; | |
5715 | + clear_user_page(page_address(page), (unsigned long)vmf->virtual_address, | |
5716 | + page); | |
5717 | + vmf->page = page; | |
5718 | + return 0; | |
5719 | +} | |
5720 | + | |
5721 | +static struct vm_operations_struct go7007_vm_ops = { | |
5722 | + .open = go7007_vm_open, | |
5723 | + .close = go7007_vm_close, | |
5724 | + .fault = go7007_vm_fault, | |
5725 | +}; | |
5726 | + | |
5727 | +static int go7007_mmap(struct file *file, struct vm_area_struct *vma) | |
5728 | +{ | |
5729 | + struct go7007_file *gofh = file->private_data; | |
5730 | + unsigned int index; | |
5731 | + | |
5732 | + if (gofh->go->status != STATUS_ONLINE) | |
5733 | + return -EIO; | |
5734 | + if (!(vma->vm_flags & VM_SHARED)) | |
5735 | + return -EINVAL; /* only support VM_SHARED mapping */ | |
5736 | + if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) | |
5737 | + return -EINVAL; /* must map exactly one full buffer */ | |
5738 | + down(&gofh->lock); | |
5739 | + index = vma->vm_pgoff / GO7007_BUF_PAGES; | |
5740 | + if (index >= gofh->buf_count) { | |
5741 | + up(&gofh->lock); | |
5742 | + return -EINVAL; /* trying to map beyond requested buffers */ | |
5743 | + } | |
5744 | + if (index * GO7007_BUF_PAGES != vma->vm_pgoff) { | |
5745 | + up(&gofh->lock); | |
5746 | + return -EINVAL; /* offset is not aligned on buffer boundary */ | |
5747 | + } | |
5748 | + if (gofh->bufs[index].mapped > 0) { | |
5749 | + up(&gofh->lock); | |
5750 | + return -EBUSY; | |
5751 | + } | |
5752 | + gofh->bufs[index].mapped = 1; | |
5753 | + gofh->bufs[index].user_addr = vma->vm_start; | |
5754 | + vma->vm_ops = &go7007_vm_ops; | |
5755 | + vma->vm_flags |= VM_DONTEXPAND; | |
5756 | + vma->vm_flags &= ~VM_IO; | |
5757 | + vma->vm_private_data = &gofh->bufs[index]; | |
5758 | + up(&gofh->lock); | |
5759 | + return 0; | |
5760 | +} | |
5761 | + | |
5762 | +static unsigned int go7007_poll(struct file *file, poll_table *wait) | |
5763 | +{ | |
5764 | + struct go7007_file *gofh = file->private_data; | |
5765 | + struct go7007_buffer *gobuf; | |
5766 | + | |
5767 | + if (list_empty(&gofh->go->stream)) | |
5768 | + return POLLERR; | |
5769 | + gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); | |
5770 | + poll_wait(file, &gofh->go->frame_waitq, wait); | |
5771 | + if (gobuf->state == BUF_STATE_DONE) | |
5772 | + return POLLIN | POLLRDNORM; | |
5773 | + return 0; | |
5774 | +} | |
5775 | + | |
5776 | +static void go7007_vfl_release(struct video_device *vfd) | |
5777 | +{ | |
5778 | + struct go7007 *go = video_get_drvdata(vfd); | |
5779 | + | |
5780 | + video_device_release(vfd); | |
5781 | + if (--go->ref_count == 0) | |
5782 | + kfree(go); | |
5783 | +} | |
5784 | + | |
5785 | +static struct file_operations go7007_fops = { | |
5786 | + .owner = THIS_MODULE, | |
5787 | + .open = go7007_open, | |
5788 | + .release = go7007_release, | |
5789 | + .ioctl = go7007_ioctl, | |
5790 | + .llseek = no_llseek, | |
5791 | + .read = go7007_read, | |
5792 | + .mmap = go7007_mmap, | |
5793 | + .poll = go7007_poll, | |
5794 | +}; | |
5795 | + | |
5796 | +static struct video_device go7007_template = { | |
5797 | + .name = "go7007", | |
5798 | + .fops = &go7007_fops, | |
5799 | + .minor = -1, | |
5800 | + .release = go7007_vfl_release, | |
5801 | +}; | |
5802 | + | |
5803 | +int go7007_v4l2_init(struct go7007 *go) | |
5804 | +{ | |
5805 | + int rv; | |
5806 | + | |
5807 | + go->video_dev = video_device_alloc(); | |
5808 | + if (go->video_dev == NULL) | |
5809 | + return -ENOMEM; | |
5810 | + memcpy(go->video_dev, &go7007_template, sizeof(go7007_template)); | |
5811 | + go->video_dev->parent = go->dev; | |
5812 | + rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); | |
5813 | + if (rv < 0) { | |
5814 | + video_device_release(go->video_dev); | |
5815 | + go->video_dev = NULL; | |
5816 | + return rv; | |
5817 | + } | |
5818 | + video_set_drvdata(go->video_dev, go); | |
5819 | + ++go->ref_count; | |
5820 | + | |
5821 | + return 0; | |
5822 | +} | |
5823 | + | |
5824 | +void go7007_v4l2_remove(struct go7007 *go) | |
5825 | +{ | |
5826 | + unsigned long flags; | |
5827 | + | |
5828 | + down(&go->hw_lock); | |
5829 | + if (go->streaming) { | |
5830 | + go->streaming = 0; | |
5831 | + go7007_stream_stop(go); | |
5832 | + spin_lock_irqsave(&go->spinlock, flags); | |
5833 | + abort_queued(go); | |
5834 | + spin_unlock_irqrestore(&go->spinlock, flags); | |
5835 | + } | |
5836 | + up(&go->hw_lock); | |
5837 | + if (go->video_dev) | |
5838 | + video_unregister_device(go->video_dev); | |
5839 | +} | |
5840 | diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/go7007/go7007.h | |
5841 | new file mode 100644 | |
5842 | index 0000000..7399c91 | |
5843 | --- /dev/null | |
5844 | +++ b/drivers/staging/go7007/go7007.h | |
5845 | @@ -0,0 +1,114 @@ | |
5846 | +/* | |
5847 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
5848 | + * | |
5849 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
5850 | + * copy of this software and the associated README documentation file (the | |
5851 | + * "Software"), to deal in the Software without restriction, including | |
5852 | + * without limitation the rights to use, copy, modify, merge, publish, | |
5853 | + * distribute, sublicense, and/or sell copies of the Software, and to | |
5854 | + * permit persons to whom the Software is furnished to do so. | |
5855 | + * | |
5856 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
5857 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
5858 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
5859 | + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
5860 | + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
5861 | + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
5862 | + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
5863 | + */ | |
5864 | + | |
5865 | +/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS | |
5866 | + * to select between MPEG1, MPEG2, and MPEG4 */ | |
5867 | +#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */ | |
5868 | + | |
5869 | +/* These will be replaced with a better interface | |
5870 | + * soon, so don't get too attached to them */ | |
5871 | +#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int) | |
5872 | +#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int) | |
5873 | + | |
5874 | +enum go7007_aspect_ratio { | |
5875 | + GO7007_ASPECT_RATIO_1_1 = 0, | |
5876 | + GO7007_ASPECT_RATIO_4_3_NTSC = 1, | |
5877 | + GO7007_ASPECT_RATIO_4_3_PAL = 2, | |
5878 | + GO7007_ASPECT_RATIO_16_9_NTSC = 3, | |
5879 | + GO7007_ASPECT_RATIO_16_9_PAL = 4, | |
5880 | +}; | |
5881 | + | |
5882 | +/* Used to set generic compression parameters */ | |
5883 | +struct go7007_comp_params { | |
5884 | + __u32 gop_size; | |
5885 | + __u32 max_b_frames; | |
5886 | + enum go7007_aspect_ratio aspect_ratio; | |
5887 | + __u32 flags; | |
5888 | + __u32 reserved[8]; | |
5889 | +}; | |
5890 | + | |
5891 | +#define GO7007_COMP_CLOSED_GOP 0x00000001 | |
5892 | +#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002 | |
5893 | + | |
5894 | +enum go7007_mpeg_video_standard { | |
5895 | + GO7007_MPEG_VIDEO_MPEG1 = 0, | |
5896 | + GO7007_MPEG_VIDEO_MPEG2 = 1, | |
5897 | + GO7007_MPEG_VIDEO_MPEG4 = 2, | |
5898 | +}; | |
5899 | + | |
5900 | +/* Used to set parameters for V4L2_PIX_FMT_MPEG format */ | |
5901 | +struct go7007_mpeg_params { | |
5902 | + enum go7007_mpeg_video_standard mpeg_video_standard; | |
5903 | + __u32 flags; | |
5904 | + __u32 pali; | |
5905 | + __u32 reserved[8]; | |
5906 | +}; | |
5907 | + | |
5908 | +#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001 | |
5909 | +#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002 | |
5910 | +#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004 | |
5911 | + | |
5912 | +#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali)) | |
5913 | + | |
5914 | +#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48) | |
5915 | + | |
5916 | +#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08) | |
5917 | +#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01) | |
5918 | +#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02) | |
5919 | +#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03) | |
5920 | +#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91) | |
5921 | +#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92) | |
5922 | +#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93) | |
5923 | +#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94) | |
5924 | +#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0) | |
5925 | +#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1) | |
5926 | +#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2) | |
5927 | +#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3) | |
5928 | +#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4) | |
5929 | +#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5) | |
5930 | + | |
5931 | +struct go7007_md_params { | |
5932 | + __u16 region; | |
5933 | + __u16 trigger; | |
5934 | + __u16 pixel_threshold; | |
5935 | + __u16 motion_threshold; | |
5936 | + __u32 reserved[8]; | |
5937 | +}; | |
5938 | + | |
5939 | +struct go7007_md_region { | |
5940 | + __u16 region; | |
5941 | + __u16 flags; | |
5942 | + struct v4l2_clip *clips; | |
5943 | + __u32 reserved[8]; | |
5944 | +}; | |
5945 | + | |
5946 | +#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \ | |
5947 | + struct go7007_mpeg_params) | |
5948 | +#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \ | |
5949 | + struct go7007_mpeg_params) | |
5950 | +#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \ | |
5951 | + struct go7007_comp_params) | |
5952 | +#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \ | |
5953 | + struct go7007_comp_params) | |
5954 | +#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \ | |
5955 | + struct go7007_md_params) | |
5956 | +#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \ | |
5957 | + struct go7007_md_params) | |
5958 | +#define GO7007IOC_S_MD_REGION _IOW('V', BASE_VIDIOC_PRIVATE + 8, \ | |
5959 | + struct go7007_md_region) | |
5960 | diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c | |
5961 | new file mode 100644 | |
5962 | index 0000000..c4a6d8e | |
5963 | --- /dev/null | |
5964 | +++ b/drivers/staging/go7007/saa7134-go7007.c | |
5965 | @@ -0,0 +1,484 @@ | |
5966 | +/* | |
5967 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
5968 | + * | |
5969 | + * This program is free software; you can redistribute it and/or modify | |
5970 | + * it under the terms of the GNU General Public License (Version 2) as | |
5971 | + * published by the Free Software Foundation. | |
5972 | + * | |
5973 | + * This program is distributed in the hope that it will be useful, | |
5974 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
5975 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
5976 | + * GNU General Public License for more details. | |
5977 | + * | |
5978 | + * You should have received a copy of the GNU General Public License | |
5979 | + * along with this program; if not, write to the Free Software Foundation, | |
5980 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
5981 | + */ | |
5982 | + | |
5983 | +#include <linux/module.h> | |
5984 | +#include <linux/kernel.h> | |
5985 | +#include <linux/init.h> | |
5986 | +#include <linux/spinlock.h> | |
5987 | +#include <linux/wait.h> | |
5988 | +#include <linux/list.h> | |
5989 | +#include <linux/slab.h> | |
5990 | +#include <linux/time.h> | |
5991 | +#include <linux/mm.h> | |
5992 | +#include <linux/usb.h> | |
5993 | +#include <linux/i2c.h> | |
5994 | +#include <asm/byteorder.h> | |
5995 | +#include <media/audiochip.h> | |
5996 | + | |
5997 | +#include "saa7134-reg.h" | |
5998 | +#include "saa7134.h" | |
5999 | +#include "go7007-priv.h" | |
6000 | + | |
6001 | +#define GO7007_HPI_DEBUG | |
6002 | + | |
6003 | +enum hpi_address { | |
6004 | + HPI_ADDR_VIDEO_BUFFER = 0xe4, | |
6005 | + HPI_ADDR_INIT_BUFFER = 0xea, | |
6006 | + HPI_ADDR_INTR_RET_VALUE = 0xee, | |
6007 | + HPI_ADDR_INTR_RET_DATA = 0xec, | |
6008 | + HPI_ADDR_INTR_STATUS = 0xf4, | |
6009 | + HPI_ADDR_INTR_WR_PARAM = 0xf6, | |
6010 | + HPI_ADDR_INTR_WR_INDEX = 0xf8, | |
6011 | +}; | |
6012 | + | |
6013 | +enum gpio_command { | |
6014 | + GPIO_COMMAND_RESET = 0x00, /* 000b */ | |
6015 | + GPIO_COMMAND_REQ1 = 0x04, /* 001b */ | |
6016 | + GPIO_COMMAND_WRITE = 0x20, /* 010b */ | |
6017 | + GPIO_COMMAND_REQ2 = 0x24, /* 011b */ | |
6018 | + GPIO_COMMAND_READ = 0x80, /* 100b */ | |
6019 | + GPIO_COMMAND_VIDEO = 0x84, /* 101b */ | |
6020 | + GPIO_COMMAND_IDLE = 0xA0, /* 110b */ | |
6021 | + GPIO_COMMAND_ADDR = 0xA4, /* 111b */ | |
6022 | +}; | |
6023 | + | |
6024 | +struct saa7134_go7007 { | |
6025 | + struct saa7134_dev *dev; | |
6026 | + u8 *top; | |
6027 | + u8 *bottom; | |
6028 | + dma_addr_t top_dma; | |
6029 | + dma_addr_t bottom_dma; | |
6030 | +}; | |
6031 | + | |
6032 | +static struct go7007_board_info board_voyager = { | |
6033 | + .firmware = "go7007tv.bin", | |
6034 | + .flags = 0, | |
6035 | + .sensor_flags = GO7007_SENSOR_656 | | |
6036 | + GO7007_SENSOR_VALID_ENABLE | | |
6037 | + GO7007_SENSOR_TV | | |
6038 | + GO7007_SENSOR_VBI, | |
6039 | + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
6040 | + GO7007_AUDIO_WORD_16, | |
6041 | + .audio_rate = 48000, | |
6042 | + .audio_bclk_div = 8, | |
6043 | + .audio_main_div = 2, | |
6044 | + .hpi_buffer_cap = 7, | |
6045 | + .num_inputs = 1, | |
6046 | + .inputs = { | |
6047 | + { | |
6048 | + .name = "SAA7134", | |
6049 | + }, | |
6050 | + }, | |
6051 | +}; | |
6052 | + | |
6053 | +/********************* Driver for GPIO HPI interface *********************/ | |
6054 | + | |
6055 | +static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) | |
6056 | +{ | |
6057 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
6058 | + | |
6059 | + /* Write HPI address */ | |
6060 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); | |
6061 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
6062 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6063 | + | |
6064 | + /* Write low byte */ | |
6065 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); | |
6066 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
6067 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6068 | + | |
6069 | + /* Write high byte */ | |
6070 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); | |
6071 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
6072 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6073 | + | |
6074 | + return 0; | |
6075 | +} | |
6076 | + | |
6077 | +static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) | |
6078 | +{ | |
6079 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
6080 | + | |
6081 | + /* Write HPI address */ | |
6082 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); | |
6083 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
6084 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6085 | + | |
6086 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); | |
6087 | + | |
6088 | + /* Read low byte */ | |
6089 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); | |
6090 | + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6091 | + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6092 | + *data = saa_readb(SAA7134_GPIO_GPSTATUS0); | |
6093 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6094 | + | |
6095 | + /* Read high byte */ | |
6096 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); | |
6097 | + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6098 | + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6099 | + *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; | |
6100 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6101 | + | |
6102 | + return 0; | |
6103 | +} | |
6104 | + | |
6105 | +static int saa7134_go7007_interface_reset(struct go7007 *go) | |
6106 | +{ | |
6107 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6108 | + struct saa7134_dev *dev = saa->dev; | |
6109 | + u32 status; | |
6110 | + u16 intr_val, intr_data; | |
6111 | + int count = 20; | |
6112 | + | |
6113 | + saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ | |
6114 | + saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); | |
6115 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
6116 | + | |
6117 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
6118 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); | |
6119 | + msleep(1); | |
6120 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
6121 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); | |
6122 | + msleep(10); | |
6123 | + | |
6124 | + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6125 | + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6126 | + | |
6127 | + status = saa_readb(SAA7134_GPIO_GPSTATUS2); | |
6128 | + /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */ | |
6129 | + | |
6130 | + /* enter command mode...(?) */ | |
6131 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
6132 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); | |
6133 | + | |
6134 | + do { | |
6135 | + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6136 | + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
6137 | + status = saa_readb(SAA7134_GPIO_GPSTATUS2); | |
6138 | + /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ | |
6139 | + } while (--count > 0); | |
6140 | + | |
6141 | + /* Wait for an interrupt to indicate successful hardware reset */ | |
6142 | + if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || | |
6143 | + (intr_val & ~0x1) != 0x55aa) { | |
6144 | + printk(KERN_ERR | |
6145 | + "saa7134-go7007: unable to reset the GO7007\n"); | |
6146 | + return -1; | |
6147 | + } | |
6148 | + return 0; | |
6149 | +} | |
6150 | + | |
6151 | +static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) | |
6152 | +{ | |
6153 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6154 | + struct saa7134_dev *dev = saa->dev; | |
6155 | + int i; | |
6156 | + u16 status_reg; | |
6157 | + | |
6158 | +#ifdef GO7007_HPI_DEBUG | |
6159 | + printk(KERN_DEBUG | |
6160 | + "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); | |
6161 | +#endif | |
6162 | + | |
6163 | + for (i = 0; i < 100; ++i) { | |
6164 | + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); | |
6165 | + if (!(status_reg & 0x0010)) | |
6166 | + break; | |
6167 | + msleep(10); | |
6168 | + } | |
6169 | + if (i == 100) { | |
6170 | + printk(KERN_ERR | |
6171 | + "saa7134-go7007: device is hung, status reg = 0x%04x\n", | |
6172 | + status_reg); | |
6173 | + return -1; | |
6174 | + } | |
6175 | + gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); | |
6176 | + gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); | |
6177 | + | |
6178 | + return 0; | |
6179 | +} | |
6180 | + | |
6181 | +static int saa7134_go7007_read_interrupt(struct go7007 *go) | |
6182 | +{ | |
6183 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6184 | + struct saa7134_dev *dev = saa->dev; | |
6185 | + | |
6186 | + /* XXX we need to wait if there is no interrupt available */ | |
6187 | + go->interrupt_available = 1; | |
6188 | + gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); | |
6189 | + gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); | |
6190 | +#ifdef GO7007_HPI_DEBUG | |
6191 | + printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n", | |
6192 | + go->interrupt_value, go->interrupt_data); | |
6193 | +#endif | |
6194 | + return 0; | |
6195 | +} | |
6196 | + | |
6197 | +static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, | |
6198 | + unsigned long status) | |
6199 | +{ | |
6200 | + struct go7007 *go = video_get_drvdata(dev->empress_dev); | |
6201 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6202 | + | |
6203 | + if (!go->streaming) | |
6204 | + return; | |
6205 | + if (0 != (status & 0x000f0000)) | |
6206 | + printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n", | |
6207 | + (status >> 16) & 0x0f); | |
6208 | + if (status & 0x100000) { | |
6209 | + dma_sync_single(&dev->pci->dev, | |
6210 | + saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); | |
6211 | + go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); | |
6212 | + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); | |
6213 | + } else { | |
6214 | + dma_sync_single(&dev->pci->dev, | |
6215 | + saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); | |
6216 | + go7007_parse_video_stream(go, saa->top, PAGE_SIZE); | |
6217 | + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); | |
6218 | + } | |
6219 | +} | |
6220 | + | |
6221 | +static int saa7134_go7007_stream_start(struct go7007 *go) | |
6222 | +{ | |
6223 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6224 | + struct saa7134_dev *dev = saa->dev; | |
6225 | + | |
6226 | + saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), | |
6227 | + 0, PAGE_SIZE, DMA_FROM_DEVICE); | |
6228 | + if (!saa->top_dma) | |
6229 | + return -ENOMEM; | |
6230 | + saa->bottom_dma = dma_map_page(&dev->pci->dev, | |
6231 | + virt_to_page(saa->bottom), | |
6232 | + 0, PAGE_SIZE, DMA_FROM_DEVICE); | |
6233 | + if (!saa->bottom_dma) { | |
6234 | + dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, | |
6235 | + DMA_FROM_DEVICE); | |
6236 | + return -ENOMEM; | |
6237 | + } | |
6238 | + | |
6239 | + saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); | |
6240 | + saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); | |
6241 | + | |
6242 | + /* Set HPI interface for video */ | |
6243 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
6244 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); | |
6245 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
6246 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); | |
6247 | + | |
6248 | + /* Enable TS interface */ | |
6249 | + saa_writeb(SAA7134_TS_PARALLEL, 0xe6); | |
6250 | + | |
6251 | + /* Reset TS interface */ | |
6252 | + saa_setb(SAA7134_TS_SERIAL1, 0x01); | |
6253 | + saa_clearb(SAA7134_TS_SERIAL1, 0x01); | |
6254 | + | |
6255 | + /* Set up transfer block size */ | |
6256 | + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); | |
6257 | + saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); | |
6258 | + saa_writeb(SAA7134_TS_DMA1, 0); | |
6259 | + saa_writeb(SAA7134_TS_DMA2, 0); | |
6260 | + | |
6261 | + /* Enable video streaming mode */ | |
6262 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); | |
6263 | + | |
6264 | + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); | |
6265 | + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); | |
6266 | + saa_writel(SAA7134_RS_PITCH(5), 128); | |
6267 | + saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); | |
6268 | + | |
6269 | + /* Enable TS FIFO */ | |
6270 | + saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); | |
6271 | + | |
6272 | + /* Enable DMA IRQ */ | |
6273 | + saa_setl(SAA7134_IRQ1, | |
6274 | + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); | |
6275 | + | |
6276 | + return 0; | |
6277 | +} | |
6278 | + | |
6279 | +static int saa7134_go7007_stream_stop(struct go7007 *go) | |
6280 | +{ | |
6281 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6282 | + struct saa7134_dev *dev = saa->dev; | |
6283 | + | |
6284 | + /* Shut down TS FIFO */ | |
6285 | + saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); | |
6286 | + | |
6287 | + /* Disable DMA IRQ */ | |
6288 | + saa_clearl(SAA7134_IRQ1, | |
6289 | + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); | |
6290 | + | |
6291 | + /* Disable TS interface */ | |
6292 | + saa_clearb(SAA7134_TS_PARALLEL, 0x80); | |
6293 | + | |
6294 | + dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, | |
6295 | + DMA_FROM_DEVICE); | |
6296 | + dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, | |
6297 | + DMA_FROM_DEVICE); | |
6298 | + | |
6299 | + return 0; | |
6300 | +} | |
6301 | + | |
6302 | +static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) | |
6303 | +{ | |
6304 | + struct saa7134_go7007 *saa = go->hpi_context; | |
6305 | + struct saa7134_dev *dev = saa->dev; | |
6306 | + u16 status_reg; | |
6307 | + int i; | |
6308 | + | |
6309 | +#ifdef GO7007_HPI_DEBUG | |
6310 | + printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer " | |
6311 | + "sending %d bytes\n", len); | |
6312 | +#endif | |
6313 | + | |
6314 | + while (len > 0) { | |
6315 | + i = len > 64 ? 64 : len; | |
6316 | + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
6317 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); | |
6318 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
6319 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6320 | + while (i-- > 0) { | |
6321 | + saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); | |
6322 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
6323 | + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
6324 | + ++data; | |
6325 | + --len; | |
6326 | + } | |
6327 | + for (i = 0; i < 100; ++i) { | |
6328 | + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); | |
6329 | + if (!(status_reg & 0x0002)) | |
6330 | + break; | |
6331 | + } | |
6332 | + if (i == 100) { | |
6333 | + printk(KERN_ERR "saa7134-go7007: device is hung, " | |
6334 | + "status reg = 0x%04x\n", status_reg); | |
6335 | + return -1; | |
6336 | + } | |
6337 | + } | |
6338 | + return 0; | |
6339 | +} | |
6340 | + | |
6341 | +static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { | |
6342 | + .interface_reset = saa7134_go7007_interface_reset, | |
6343 | + .write_interrupt = saa7134_go7007_write_interrupt, | |
6344 | + .read_interrupt = saa7134_go7007_read_interrupt, | |
6345 | + .stream_start = saa7134_go7007_stream_start, | |
6346 | + .stream_stop = saa7134_go7007_stream_stop, | |
6347 | + .send_firmware = saa7134_go7007_send_firmware, | |
6348 | +}; | |
6349 | + | |
6350 | +/********************* Add/remove functions *********************/ | |
6351 | + | |
6352 | +static int saa7134_go7007_init(struct saa7134_dev *dev) | |
6353 | +{ | |
6354 | + struct go7007 *go; | |
6355 | + struct saa7134_go7007 *saa; | |
6356 | + | |
6357 | + printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); | |
6358 | + | |
6359 | + saa = kmalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); | |
6360 | + if (saa == NULL) | |
6361 | + return -ENOMEM; | |
6362 | + memset(saa, 0, sizeof(struct saa7134_go7007)); | |
6363 | + | |
6364 | + /* Allocate a couple pages for receiving the compressed stream */ | |
6365 | + saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); | |
6366 | + if (!saa->top) | |
6367 | + goto allocfail; | |
6368 | + saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); | |
6369 | + if (!saa->bottom) | |
6370 | + goto allocfail; | |
6371 | + | |
6372 | + go = go7007_alloc(&board_voyager, &dev->pci->dev); | |
6373 | + if (go == NULL) | |
6374 | + goto allocfail; | |
6375 | + go->board_id = GO7007_BOARDID_PCI_VOYAGER; | |
6376 | + strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); | |
6377 | + go->hpi_ops = &saa7134_go7007_hpi_ops; | |
6378 | + go->hpi_context = saa; | |
6379 | + saa->dev = dev; | |
6380 | + | |
6381 | + /* Boot the GO7007 */ | |
6382 | + if (go7007_boot_encoder(go, go->board_info->flags & | |
6383 | + GO7007_BOARD_USE_ONBOARD_I2C) < 0) | |
6384 | + goto initfail; | |
6385 | + | |
6386 | + /* Do any final GO7007 initialization, then register the | |
6387 | + * V4L2 and ALSA interfaces */ | |
6388 | + if (go7007_register_encoder(go) < 0) | |
6389 | + goto initfail; | |
6390 | + dev->empress_dev = go->video_dev; | |
6391 | + video_set_drvdata(dev->empress_dev, go); | |
6392 | + | |
6393 | + go->status = STATUS_ONLINE; | |
6394 | + return 0; | |
6395 | + | |
6396 | +initfail: | |
6397 | + go->status = STATUS_SHUTDOWN; | |
6398 | + return 0; | |
6399 | + | |
6400 | +allocfail: | |
6401 | + if (saa->top) | |
6402 | + free_page((unsigned long)saa->top); | |
6403 | + if (saa->bottom) | |
6404 | + free_page((unsigned long)saa->bottom); | |
6405 | + kfree(saa); | |
6406 | + return -ENOMEM; | |
6407 | +} | |
6408 | + | |
6409 | +static int saa7134_go7007_fini(struct saa7134_dev *dev) | |
6410 | +{ | |
6411 | + struct go7007 *go; | |
6412 | + struct saa7134_go7007 *saa; | |
6413 | + | |
6414 | + if (NULL == dev->empress_dev) | |
6415 | + return 0; | |
6416 | + | |
6417 | + go = video_get_drvdata(dev->empress_dev); | |
6418 | + saa = go->hpi_context; | |
6419 | + go->status = STATUS_SHUTDOWN; | |
6420 | + free_page((unsigned long)saa->top); | |
6421 | + free_page((unsigned long)saa->bottom); | |
6422 | + kfree(saa); | |
6423 | + go7007_remove(go); | |
6424 | + dev->empress_dev = NULL; | |
6425 | + | |
6426 | + return 0; | |
6427 | +} | |
6428 | + | |
6429 | +static struct saa7134_mpeg_ops saa7134_go7007_ops = { | |
6430 | + .type = SAA7134_MPEG_GO7007, | |
6431 | + .init = saa7134_go7007_init, | |
6432 | + .fini = saa7134_go7007_fini, | |
6433 | + .irq_ts_done = saa7134_go7007_irq_ts_done, | |
6434 | +}; | |
6435 | + | |
6436 | +static int __init saa7134_go7007_mod_init(void) | |
6437 | +{ | |
6438 | + return saa7134_ts_register(&saa7134_go7007_ops); | |
6439 | +} | |
6440 | + | |
6441 | +static void __exit saa7134_go7007_mod_cleanup(void) | |
6442 | +{ | |
6443 | + saa7134_ts_unregister(&saa7134_go7007_ops); | |
6444 | +} | |
6445 | + | |
6446 | +module_init(saa7134_go7007_mod_init); | |
6447 | +module_exit(saa7134_go7007_mod_cleanup); | |
6448 | + | |
6449 | +MODULE_LICENSE("GPL v2"); | |
6450 | diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c | |
6451 | new file mode 100644 | |
6452 | index 0000000..f5cac08 | |
6453 | --- /dev/null | |
6454 | +++ b/drivers/staging/go7007/snd-go7007.c | |
6455 | @@ -0,0 +1,305 @@ | |
6456 | +/* | |
6457 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
6458 | + * | |
6459 | + * This program is free software; you can redistribute it and/or modify | |
6460 | + * it under the terms of the GNU General Public License (Version 2) as | |
6461 | + * published by the Free Software Foundation. | |
6462 | + * | |
6463 | + * This program is distributed in the hope that it will be useful, | |
6464 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6465 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6466 | + * GNU General Public License for more details. | |
6467 | + * | |
6468 | + * You should have received a copy of the GNU General Public License | |
6469 | + * along with this program; if not, write to the Free Software Foundation, | |
6470 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
6471 | + */ | |
6472 | + | |
6473 | +#include <linux/kernel.h> | |
6474 | +#include <linux/module.h> | |
6475 | +#include <linux/version.h> | |
6476 | +#include <linux/moduleparam.h> | |
6477 | +#include <linux/init.h> | |
6478 | +#include <linux/spinlock.h> | |
6479 | +#include <linux/delay.h> | |
6480 | +#include <linux/sched.h> | |
6481 | +#include <linux/vmalloc.h> | |
6482 | +#include <linux/time.h> | |
6483 | +#include <linux/mm.h> | |
6484 | +#include <linux/i2c.h> | |
6485 | +#include <linux/semaphore.h> | |
6486 | +#include <linux/uaccess.h> | |
6487 | +#include <asm/system.h> | |
6488 | +#include <sound/core.h> | |
6489 | +#include <sound/pcm.h> | |
6490 | +#include <sound/initval.h> | |
6491 | + | |
6492 | +#include "go7007-priv.h" | |
6493 | + | |
6494 | +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | |
6495 | +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | |
6496 | +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | |
6497 | + | |
6498 | +module_param_array(index, int, NULL, 0444); | |
6499 | +module_param_array(id, charp, NULL, 0444); | |
6500 | +module_param_array(enable, bool, NULL, 0444); | |
6501 | +MODULE_PARM_DESC(index, "Index value for the go7007 audio driver"); | |
6502 | +MODULE_PARM_DESC(index, "ID string for the go7007 audio driver"); | |
6503 | +MODULE_PARM_DESC(index, "Enable for the go7007 audio driver"); | |
6504 | + | |
6505 | +struct go7007_snd { | |
6506 | + struct snd_card *card; | |
6507 | + struct snd_pcm *pcm; | |
6508 | + struct snd_pcm_substream *substream; | |
6509 | + spinlock_t lock; | |
6510 | + int w_idx; | |
6511 | + int hw_ptr; | |
6512 | + int avail; | |
6513 | + int capturing; | |
6514 | +}; | |
6515 | + | |
6516 | +static struct snd_pcm_hardware go7007_snd_capture_hw = { | |
6517 | + .info = (SNDRV_PCM_INFO_MMAP | | |
6518 | + SNDRV_PCM_INFO_INTERLEAVED | | |
6519 | + SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
6520 | + SNDRV_PCM_INFO_MMAP_VALID), | |
6521 | + .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
6522 | + .rates = SNDRV_PCM_RATE_48000, | |
6523 | + .rate_min = 48000, | |
6524 | + .rate_max = 48000, | |
6525 | + .channels_min = 2, | |
6526 | + .channels_max = 2, | |
6527 | + .buffer_bytes_max = (128*1024), | |
6528 | + .period_bytes_min = 4096, | |
6529 | + .period_bytes_max = (128*1024), | |
6530 | + .periods_min = 1, | |
6531 | + .periods_max = 32, | |
6532 | +}; | |
6533 | + | |
6534 | +static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length) | |
6535 | +{ | |
6536 | + struct go7007_snd *gosnd = go->snd_context; | |
6537 | + struct snd_pcm_runtime *runtime = gosnd->substream->runtime; | |
6538 | + int frames = bytes_to_frames(runtime, length); | |
6539 | + | |
6540 | + spin_lock(&gosnd->lock); | |
6541 | + gosnd->hw_ptr += frames; | |
6542 | + if (gosnd->hw_ptr >= runtime->buffer_size) | |
6543 | + gosnd->hw_ptr -= runtime->buffer_size; | |
6544 | + gosnd->avail += frames; | |
6545 | + spin_unlock(&gosnd->lock); | |
6546 | + if (gosnd->w_idx + length > runtime->dma_bytes) { | |
6547 | + int cpy = runtime->dma_bytes - gosnd->w_idx; | |
6548 | + | |
6549 | + memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy); | |
6550 | + length -= cpy; | |
6551 | + buf += cpy; | |
6552 | + gosnd->w_idx = 0; | |
6553 | + } | |
6554 | + memcpy(runtime->dma_area + gosnd->w_idx, buf, length); | |
6555 | + gosnd->w_idx += length; | |
6556 | + spin_lock(&gosnd->lock); | |
6557 | + if (gosnd->avail < runtime->period_size) { | |
6558 | + spin_unlock(&gosnd->lock); | |
6559 | + return; | |
6560 | + } | |
6561 | + gosnd->avail -= runtime->period_size; | |
6562 | + spin_unlock(&gosnd->lock); | |
6563 | + if (gosnd->capturing) | |
6564 | + snd_pcm_period_elapsed(gosnd->substream); | |
6565 | +} | |
6566 | + | |
6567 | +static int go7007_snd_hw_params(struct snd_pcm_substream *substream, | |
6568 | + struct snd_pcm_hw_params *hw_params) | |
6569 | +{ | |
6570 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6571 | + unsigned int bytes; | |
6572 | + | |
6573 | + bytes = params_buffer_bytes(hw_params); | |
6574 | + if (substream->runtime->dma_bytes > 0) | |
6575 | + vfree(substream->runtime->dma_area); | |
6576 | + substream->runtime->dma_bytes = 0; | |
6577 | + substream->runtime->dma_area = vmalloc(bytes); | |
6578 | + if (substream->runtime->dma_area == NULL) | |
6579 | + return -ENOMEM; | |
6580 | + substream->runtime->dma_bytes = bytes; | |
6581 | + go->audio_deliver = parse_audio_stream_data; | |
6582 | + return 0; | |
6583 | +} | |
6584 | + | |
6585 | +static int go7007_snd_hw_free(struct snd_pcm_substream *substream) | |
6586 | +{ | |
6587 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6588 | + | |
6589 | + go->audio_deliver = NULL; | |
6590 | + if (substream->runtime->dma_bytes > 0) | |
6591 | + vfree(substream->runtime->dma_area); | |
6592 | + substream->runtime->dma_bytes = 0; | |
6593 | + return 0; | |
6594 | +} | |
6595 | + | |
6596 | +static int go7007_snd_capture_open(struct snd_pcm_substream *substream) | |
6597 | +{ | |
6598 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6599 | + struct go7007_snd *gosnd = go->snd_context; | |
6600 | + unsigned long flags; | |
6601 | + int r; | |
6602 | + | |
6603 | + spin_lock_irqsave(&gosnd->lock, flags); | |
6604 | + if (gosnd->substream == NULL) { | |
6605 | + gosnd->substream = substream; | |
6606 | + substream->runtime->hw = go7007_snd_capture_hw; | |
6607 | + r = 0; | |
6608 | + } else | |
6609 | + r = -EBUSY; | |
6610 | + spin_unlock_irqrestore(&gosnd->lock, flags); | |
6611 | + return r; | |
6612 | +} | |
6613 | + | |
6614 | +static int go7007_snd_capture_close(struct snd_pcm_substream *substream) | |
6615 | +{ | |
6616 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6617 | + struct go7007_snd *gosnd = go->snd_context; | |
6618 | + | |
6619 | + gosnd->substream = NULL; | |
6620 | + return 0; | |
6621 | +} | |
6622 | + | |
6623 | +static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream) | |
6624 | +{ | |
6625 | + return 0; | |
6626 | +} | |
6627 | + | |
6628 | +static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |
6629 | +{ | |
6630 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6631 | + struct go7007_snd *gosnd = go->snd_context; | |
6632 | + | |
6633 | + switch (cmd) { | |
6634 | + case SNDRV_PCM_TRIGGER_START: | |
6635 | + /* Just set a flag to indicate we should signal ALSA when | |
6636 | + * sound comes in */ | |
6637 | + gosnd->capturing = 1; | |
6638 | + return 0; | |
6639 | + case SNDRV_PCM_TRIGGER_STOP: | |
6640 | + gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; | |
6641 | + gosnd->capturing = 0; | |
6642 | + return 0; | |
6643 | + default: | |
6644 | + return -EINVAL; | |
6645 | + } | |
6646 | +} | |
6647 | + | |
6648 | +static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream) | |
6649 | +{ | |
6650 | + struct go7007 *go = snd_pcm_substream_chip(substream); | |
6651 | + struct go7007_snd *gosnd = go->snd_context; | |
6652 | + | |
6653 | + return gosnd->hw_ptr; | |
6654 | +} | |
6655 | + | |
6656 | +static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream, | |
6657 | + unsigned long offset) | |
6658 | +{ | |
6659 | + return vmalloc_to_page(substream->runtime->dma_area + offset); | |
6660 | +} | |
6661 | + | |
6662 | +static struct snd_pcm_ops go7007_snd_capture_ops = { | |
6663 | + .open = go7007_snd_capture_open, | |
6664 | + .close = go7007_snd_capture_close, | |
6665 | + .ioctl = snd_pcm_lib_ioctl, | |
6666 | + .hw_params = go7007_snd_hw_params, | |
6667 | + .hw_free = go7007_snd_hw_free, | |
6668 | + .prepare = go7007_snd_pcm_prepare, | |
6669 | + .trigger = go7007_snd_pcm_trigger, | |
6670 | + .pointer = go7007_snd_pcm_pointer, | |
6671 | + .page = go7007_snd_pcm_page, | |
6672 | +}; | |
6673 | + | |
6674 | +static int go7007_snd_free(struct snd_device *device) | |
6675 | +{ | |
6676 | + struct go7007 *go = device->device_data; | |
6677 | + | |
6678 | + kfree(go->snd_context); | |
6679 | + go->snd_context = NULL; | |
6680 | + if (--go->ref_count == 0) | |
6681 | + kfree(go); | |
6682 | + return 0; | |
6683 | +} | |
6684 | + | |
6685 | +static struct snd_device_ops go7007_snd_device_ops = { | |
6686 | + .dev_free = go7007_snd_free, | |
6687 | +}; | |
6688 | + | |
6689 | +int go7007_snd_init(struct go7007 *go) | |
6690 | +{ | |
6691 | + static int dev; | |
6692 | + struct go7007_snd *gosnd; | |
6693 | + int ret = 0; | |
6694 | + | |
6695 | + if (dev >= SNDRV_CARDS) | |
6696 | + return -ENODEV; | |
6697 | + if (!enable[dev]) { | |
6698 | + dev++; | |
6699 | + return -ENOENT; | |
6700 | + } | |
6701 | + gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL); | |
6702 | + if (gosnd == NULL) | |
6703 | + return -ENOMEM; | |
6704 | + spin_lock_init(&gosnd->lock); | |
6705 | + gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; | |
6706 | + gosnd->capturing = 0; | |
6707 | + gosnd->card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | |
6708 | + if (gosnd->card == NULL) { | |
6709 | + kfree(gosnd); | |
6710 | + return -ENOMEM; | |
6711 | + } | |
6712 | + ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go, | |
6713 | + &go7007_snd_device_ops); | |
6714 | + if (ret < 0) { | |
6715 | + kfree(gosnd); | |
6716 | + return ret; | |
6717 | + } | |
6718 | + snd_card_set_dev(gosnd->card, go->dev); | |
6719 | + ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm); | |
6720 | + if (ret < 0) { | |
6721 | + snd_card_free(gosnd->card); | |
6722 | + kfree(gosnd); | |
6723 | + return ret; | |
6724 | + } | |
6725 | + strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); | |
6726 | + strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); | |
6727 | + strncpy(gosnd->card->longname, gosnd->card->shortname, | |
6728 | + sizeof(gosnd->card->longname)); | |
6729 | + | |
6730 | + gosnd->pcm->private_data = go; | |
6731 | + snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE, | |
6732 | + &go7007_snd_capture_ops); | |
6733 | + | |
6734 | + ret = snd_card_register(gosnd->card); | |
6735 | + if (ret < 0) { | |
6736 | + snd_card_free(gosnd->card); | |
6737 | + kfree(gosnd); | |
6738 | + return ret; | |
6739 | + } | |
6740 | + | |
6741 | + gosnd->substream = NULL; | |
6742 | + go->snd_context = gosnd; | |
6743 | + ++dev; | |
6744 | + ++go->ref_count; | |
6745 | + | |
6746 | + return 0; | |
6747 | +} | |
6748 | +EXPORT_SYMBOL(go7007_snd_init); | |
6749 | + | |
6750 | +int go7007_snd_remove(struct go7007 *go) | |
6751 | +{ | |
6752 | + struct go7007_snd *gosnd = go->snd_context; | |
6753 | + | |
6754 | + snd_card_disconnect(gosnd->card); | |
6755 | + snd_card_free_when_closed(gosnd->card); | |
6756 | + return 0; | |
6757 | +} | |
6758 | +EXPORT_SYMBOL(go7007_snd_remove); | |
6759 | + | |
6760 | +MODULE_LICENSE("GPL v2"); | |
6761 | diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/go7007/wis-i2c.h | |
6762 | new file mode 100644 | |
6763 | index 0000000..993f658 | |
6764 | --- /dev/null | |
6765 | +++ b/drivers/staging/go7007/wis-i2c.h | |
6766 | @@ -0,0 +1,55 @@ | |
6767 | +/* | |
6768 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
6769 | + * | |
6770 | + * This program is free software; you can redistribute it and/or modify | |
6771 | + * it under the terms of the GNU General Public License (Version 2) as | |
6772 | + * published by the Free Software Foundation. | |
6773 | + * | |
6774 | + * This program is distributed in the hope that it will be useful, | |
6775 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6776 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6777 | + * GNU General Public License for more details. | |
6778 | + * | |
6779 | + * You should have received a copy of the GNU General Public License | |
6780 | + * along with this program; if not, write to the Free Software Foundation, | |
6781 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
6782 | + */ | |
6783 | + | |
6784 | +/* Temporary I2C IDs -- these need to be replaced with real registered IDs */ | |
6785 | +#define I2C_DRIVERID_WIS_SAA7115 0xf0f0 | |
6786 | +#define I2C_DRIVERID_WIS_UDA1342 0xf0f1 | |
6787 | +#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2 | |
6788 | +#define I2C_DRIVERID_WIS_TW9903 0xf0f3 | |
6789 | +#define I2C_DRIVERID_WIS_SAA7113 0xf0f4 | |
6790 | +#define I2C_DRIVERID_WIS_OV7640 0xf0f5 | |
6791 | +#define I2C_DRIVERID_WIS_TW2804 0xf0f6 | |
6792 | +#define I2C_ALGO_GO7007 0xf00000 | |
6793 | +#define I2C_ALGO_GO7007_USB 0xf10000 | |
6794 | + | |
6795 | +/* Flag to indicate that the client needs to be accessed with SCCB semantics */ | |
6796 | +/* We re-use the I2C_M_TEN value so the flag passes through the masks in the | |
6797 | + * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */ | |
6798 | +#define I2C_CLIENT_SCCB 0x10 | |
6799 | + | |
6800 | +typedef int (*found_proc) (struct i2c_adapter *, int, int); | |
6801 | +int wis_i2c_add_driver(unsigned int id, found_proc found_proc); | |
6802 | +void wis_i2c_del_driver(found_proc found_proc); | |
6803 | + | |
6804 | +int wis_i2c_probe_device(struct i2c_adapter *adapter, | |
6805 | + unsigned int id, int addr); | |
6806 | + | |
6807 | +/* Definitions for new video decoder commands */ | |
6808 | + | |
6809 | +struct video_decoder_resolution { | |
6810 | + unsigned int width; | |
6811 | + unsigned int height; | |
6812 | +}; | |
6813 | + | |
6814 | +#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) | |
6815 | +#define DECODER_SET_CHANNEL _IOW('d', 201, int) | |
6816 | + | |
6817 | +/* Sony tuner types */ | |
6818 | + | |
6819 | +#define TUNER_SONY_BTF_PG472Z 200 | |
6820 | +#define TUNER_SONY_BTF_PK467Z 201 | |
6821 | +#define TUNER_SONY_BTF_PB463Z 202 | |
6822 | diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c | |
6823 | new file mode 100644 | |
6824 | index 0000000..815615a | |
6825 | --- /dev/null | |
6826 | +++ b/drivers/staging/go7007/wis-ov7640.c | |
6827 | @@ -0,0 +1,131 @@ | |
6828 | +/* | |
6829 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
6830 | + * | |
6831 | + * This program is free software; you can redistribute it and/or modify | |
6832 | + * it under the terms of the GNU General Public License (Version 2) as | |
6833 | + * published by the Free Software Foundation. | |
6834 | + * | |
6835 | + * This program is distributed in the hope that it will be useful, | |
6836 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6837 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6838 | + * GNU General Public License for more details. | |
6839 | + * | |
6840 | + * You should have received a copy of the GNU General Public License | |
6841 | + * along with this program; if not, write to the Free Software Foundation, | |
6842 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
6843 | + */ | |
6844 | + | |
6845 | +#include <linux/module.h> | |
6846 | +#include <linux/init.h> | |
6847 | +#include <linux/version.h> | |
6848 | +#include <linux/i2c.h> | |
6849 | +#include <linux/videodev.h> | |
6850 | +#include <linux/video_decoder.h> | |
6851 | + | |
6852 | +#include "wis-i2c.h" | |
6853 | + | |
6854 | +struct wis_ov7640 { | |
6855 | + int brightness; | |
6856 | + int contrast; | |
6857 | + int saturation; | |
6858 | + int hue; | |
6859 | +}; | |
6860 | + | |
6861 | +static u8 initial_registers[] = | |
6862 | +{ | |
6863 | + 0x12, 0x80, | |
6864 | + 0x12, 0x54, | |
6865 | + 0x14, 0x24, | |
6866 | + 0x15, 0x01, | |
6867 | + 0x28, 0x20, | |
6868 | + 0x75, 0x82, | |
6869 | + 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */ | |
6870 | +}; | |
6871 | + | |
6872 | +static int write_regs(struct i2c_client *client, u8 *regs) | |
6873 | +{ | |
6874 | + int i; | |
6875 | + | |
6876 | + for (i = 0; regs[i] != 0xFF; i += 2) | |
6877 | + if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) | |
6878 | + return -1; | |
6879 | + return 0; | |
6880 | +} | |
6881 | + | |
6882 | +static struct i2c_driver wis_ov7640_driver; | |
6883 | + | |
6884 | +static struct i2c_client wis_ov7640_client_templ = { | |
6885 | + .name = "OV7640 (WIS)", | |
6886 | + .driver = &wis_ov7640_driver, | |
6887 | +}; | |
6888 | + | |
6889 | +static int wis_ov7640_detect(struct i2c_adapter *adapter, int addr, int kind) | |
6890 | +{ | |
6891 | + struct i2c_client *client; | |
6892 | + | |
6893 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
6894 | + return 0; | |
6895 | + | |
6896 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
6897 | + if (client == NULL) | |
6898 | + return -ENOMEM; | |
6899 | + memcpy(client, &wis_ov7640_client_templ, | |
6900 | + sizeof(wis_ov7640_client_templ)); | |
6901 | + client->adapter = adapter; | |
6902 | + client->addr = addr; | |
6903 | + client->flags = I2C_CLIENT_SCCB; | |
6904 | + | |
6905 | + printk(KERN_DEBUG | |
6906 | + "wis-ov7640: initializing OV7640 at address %d on %s\n", | |
6907 | + addr, adapter->name); | |
6908 | + | |
6909 | + if (write_regs(client, initial_registers) < 0) { | |
6910 | + printk(KERN_ERR "wis-ov7640: error initializing OV7640\n"); | |
6911 | + kfree(client); | |
6912 | + return 0; | |
6913 | + } | |
6914 | + | |
6915 | + i2c_attach_client(client); | |
6916 | + return 0; | |
6917 | +} | |
6918 | + | |
6919 | +static int wis_ov7640_detach(struct i2c_client *client) | |
6920 | +{ | |
6921 | + int r; | |
6922 | + | |
6923 | + r = i2c_detach_client(client); | |
6924 | + if (r < 0) | |
6925 | + return r; | |
6926 | + | |
6927 | + kfree(client); | |
6928 | + return 0; | |
6929 | +} | |
6930 | + | |
6931 | +static struct i2c_driver wis_ov7640_driver = { | |
6932 | + .driver = { | |
6933 | + .name = "WIS OV7640 I2C driver", | |
6934 | + }, | |
6935 | + .id = I2C_DRIVERID_WIS_OV7640, | |
6936 | + .detach_client = wis_ov7640_detach, | |
6937 | +}; | |
6938 | + | |
6939 | +static int __init wis_ov7640_init(void) | |
6940 | +{ | |
6941 | + int r; | |
6942 | + | |
6943 | + r = i2c_add_driver(&wis_ov7640_driver); | |
6944 | + if (r < 0) | |
6945 | + return r; | |
6946 | + return wis_i2c_add_driver(wis_ov7640_driver.id, wis_ov7640_detect); | |
6947 | +} | |
6948 | + | |
6949 | +static void __exit wis_ov7640_cleanup(void) | |
6950 | +{ | |
6951 | + wis_i2c_del_driver(wis_ov7640_detect); | |
6952 | + i2c_del_driver(&wis_ov7640_driver); | |
6953 | +} | |
6954 | + | |
6955 | +module_init(wis_ov7640_init); | |
6956 | +module_exit(wis_ov7640_cleanup); | |
6957 | + | |
6958 | +MODULE_LICENSE("GPL v2"); | |
6959 | diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c | |
6960 | new file mode 100644 | |
6961 | index 0000000..4b14ca8 | |
6962 | --- /dev/null | |
6963 | +++ b/drivers/staging/go7007/wis-saa7113.c | |
6964 | @@ -0,0 +1,363 @@ | |
6965 | +/* | |
6966 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
6967 | + * | |
6968 | + * This program is free software; you can redistribute it and/or modify | |
6969 | + * it under the terms of the GNU General Public License (Version 2) as | |
6970 | + * published by the Free Software Foundation. | |
6971 | + * | |
6972 | + * This program is distributed in the hope that it will be useful, | |
6973 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6974 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6975 | + * GNU General Public License for more details. | |
6976 | + * | |
6977 | + * You should have received a copy of the GNU General Public License | |
6978 | + * along with this program; if not, write to the Free Software Foundation, | |
6979 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
6980 | + */ | |
6981 | + | |
6982 | +#include <linux/module.h> | |
6983 | +#include <linux/init.h> | |
6984 | +#include <linux/version.h> | |
6985 | +#include <linux/i2c.h> | |
6986 | +#include <linux/videodev.h> | |
6987 | +#include <linux/video_decoder.h> | |
6988 | +#include <linux/ioctl.h> | |
6989 | + | |
6990 | +#include "wis-i2c.h" | |
6991 | + | |
6992 | +struct wis_saa7113 { | |
6993 | + int norm; | |
6994 | + int brightness; | |
6995 | + int contrast; | |
6996 | + int saturation; | |
6997 | + int hue; | |
6998 | +}; | |
6999 | + | |
7000 | +static u8 initial_registers[] = | |
7001 | +{ | |
7002 | + 0x01, 0x08, | |
7003 | + 0x02, 0xc0, | |
7004 | + 0x03, 0x33, | |
7005 | + 0x04, 0x00, | |
7006 | + 0x05, 0x00, | |
7007 | + 0x06, 0xe9, | |
7008 | + 0x07, 0x0d, | |
7009 | + 0x08, 0xd8, | |
7010 | + 0x09, 0x40, | |
7011 | + 0x0a, 0x80, | |
7012 | + 0x0b, 0x47, | |
7013 | + 0x0c, 0x40, | |
7014 | + 0x0d, 0x00, | |
7015 | + 0x0e, 0x01, | |
7016 | + 0x0f, 0x2a, | |
7017 | + 0x10, 0x40, | |
7018 | + 0x11, 0x0c, | |
7019 | + 0x12, 0xfe, | |
7020 | + 0x13, 0x00, | |
7021 | + 0x14, 0x00, | |
7022 | + 0x15, 0x04, | |
7023 | + 0x16, 0x00, | |
7024 | + 0x17, 0x00, | |
7025 | + 0x18, 0x00, | |
7026 | + 0x19, 0x00, | |
7027 | + 0x1a, 0x00, | |
7028 | + 0x1b, 0x00, | |
7029 | + 0x1c, 0x00, | |
7030 | + 0x1d, 0x00, | |
7031 | + 0x1e, 0x00, | |
7032 | + 0x1f, 0xc8, | |
7033 | + 0x40, 0x00, | |
7034 | + 0x41, 0xff, | |
7035 | + 0x42, 0xff, | |
7036 | + 0x43, 0xff, | |
7037 | + 0x44, 0xff, | |
7038 | + 0x45, 0xff, | |
7039 | + 0x46, 0xff, | |
7040 | + 0x47, 0xff, | |
7041 | + 0x48, 0xff, | |
7042 | + 0x49, 0xff, | |
7043 | + 0x4a, 0xff, | |
7044 | + 0x4b, 0xff, | |
7045 | + 0x4c, 0xff, | |
7046 | + 0x4d, 0xff, | |
7047 | + 0x4e, 0xff, | |
7048 | + 0x4f, 0xff, | |
7049 | + 0x50, 0xff, | |
7050 | + 0x51, 0xff, | |
7051 | + 0x52, 0xff, | |
7052 | + 0x53, 0xff, | |
7053 | + 0x54, 0xff, | |
7054 | + 0x55, 0xff, | |
7055 | + 0x56, 0xff, | |
7056 | + 0x57, 0xff, | |
7057 | + 0x58, 0x00, | |
7058 | + 0x59, 0x54, | |
7059 | + 0x5a, 0x07, | |
7060 | + 0x5b, 0x83, | |
7061 | + 0x5c, 0x00, | |
7062 | + 0x5d, 0x00, | |
7063 | + 0x5e, 0x00, | |
7064 | + 0x5f, 0x00, | |
7065 | + 0x60, 0x00, | |
7066 | + 0x61, 0x00, | |
7067 | + 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ | |
7068 | +}; | |
7069 | + | |
7070 | +static int write_reg(struct i2c_client *client, u8 reg, u8 value) | |
7071 | +{ | |
7072 | + return i2c_smbus_write_byte_data(client, reg, value); | |
7073 | +} | |
7074 | + | |
7075 | +static int write_regs(struct i2c_client *client, u8 *regs) | |
7076 | +{ | |
7077 | + int i; | |
7078 | + | |
7079 | + for (i = 0; regs[i] != 0x00; i += 2) | |
7080 | + if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) | |
7081 | + return -1; | |
7082 | + return 0; | |
7083 | +} | |
7084 | + | |
7085 | +static int wis_saa7113_command(struct i2c_client *client, | |
7086 | + unsigned int cmd, void *arg) | |
7087 | +{ | |
7088 | + struct wis_saa7113 *dec = i2c_get_clientdata(client); | |
7089 | + | |
7090 | + switch (cmd) { | |
7091 | + case DECODER_SET_INPUT: | |
7092 | + { | |
7093 | + int *input = arg; | |
7094 | + | |
7095 | + i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); | |
7096 | + i2c_smbus_write_byte_data(client, 0x09, | |
7097 | + *input < 6 ? 0x40 : 0x80); | |
7098 | + break; | |
7099 | + } | |
7100 | + case DECODER_SET_NORM: | |
7101 | + { | |
7102 | + int *input = arg; | |
7103 | + dec->norm = *input; | |
7104 | + switch (dec->norm) { | |
7105 | + case VIDEO_MODE_PAL: | |
7106 | + write_reg(client, 0x0e, 0x01); | |
7107 | + write_reg(client, 0x10, 0x48); | |
7108 | + break; | |
7109 | + case VIDEO_MODE_NTSC: | |
7110 | + write_reg(client, 0x0e, 0x01); | |
7111 | + write_reg(client, 0x10, 0x40); | |
7112 | + break; | |
7113 | + case VIDEO_MODE_SECAM: | |
7114 | + write_reg(client, 0x0e, 0x50); | |
7115 | + write_reg(client, 0x10, 0x48); | |
7116 | + break; | |
7117 | + } | |
7118 | + break; | |
7119 | + } | |
7120 | + case VIDIOC_QUERYCTRL: | |
7121 | + { | |
7122 | + struct v4l2_queryctrl *ctrl = arg; | |
7123 | + | |
7124 | + switch (ctrl->id) { | |
7125 | + case V4L2_CID_BRIGHTNESS: | |
7126 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7127 | + strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); | |
7128 | + ctrl->minimum = 0; | |
7129 | + ctrl->maximum = 255; | |
7130 | + ctrl->step = 1; | |
7131 | + ctrl->default_value = 128; | |
7132 | + ctrl->flags = 0; | |
7133 | + break; | |
7134 | + case V4L2_CID_CONTRAST: | |
7135 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7136 | + strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); | |
7137 | + ctrl->minimum = 0; | |
7138 | + ctrl->maximum = 127; | |
7139 | + ctrl->step = 1; | |
7140 | + ctrl->default_value = 71; | |
7141 | + ctrl->flags = 0; | |
7142 | + break; | |
7143 | + case V4L2_CID_SATURATION: | |
7144 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7145 | + strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); | |
7146 | + ctrl->minimum = 0; | |
7147 | + ctrl->maximum = 127; | |
7148 | + ctrl->step = 1; | |
7149 | + ctrl->default_value = 64; | |
7150 | + ctrl->flags = 0; | |
7151 | + break; | |
7152 | + case V4L2_CID_HUE: | |
7153 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7154 | + strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); | |
7155 | + ctrl->minimum = -128; | |
7156 | + ctrl->maximum = 127; | |
7157 | + ctrl->step = 1; | |
7158 | + ctrl->default_value = 0; | |
7159 | + ctrl->flags = 0; | |
7160 | + break; | |
7161 | + } | |
7162 | + break; | |
7163 | + } | |
7164 | + case VIDIOC_S_CTRL: | |
7165 | + { | |
7166 | + struct v4l2_control *ctrl = arg; | |
7167 | + | |
7168 | + switch (ctrl->id) { | |
7169 | + case V4L2_CID_BRIGHTNESS: | |
7170 | + if (ctrl->value > 255) | |
7171 | + dec->brightness = 255; | |
7172 | + else if (ctrl->value < 0) | |
7173 | + dec->brightness = 0; | |
7174 | + else | |
7175 | + dec->brightness = ctrl->value; | |
7176 | + write_reg(client, 0x0a, dec->brightness); | |
7177 | + break; | |
7178 | + case V4L2_CID_CONTRAST: | |
7179 | + if (ctrl->value > 127) | |
7180 | + dec->contrast = 127; | |
7181 | + else if (ctrl->value < 0) | |
7182 | + dec->contrast = 0; | |
7183 | + else | |
7184 | + dec->contrast = ctrl->value; | |
7185 | + write_reg(client, 0x0b, dec->contrast); | |
7186 | + break; | |
7187 | + case V4L2_CID_SATURATION: | |
7188 | + if (ctrl->value > 127) | |
7189 | + dec->saturation = 127; | |
7190 | + else if (ctrl->value < 0) | |
7191 | + dec->saturation = 0; | |
7192 | + else | |
7193 | + dec->saturation = ctrl->value; | |
7194 | + write_reg(client, 0x0c, dec->saturation); | |
7195 | + break; | |
7196 | + case V4L2_CID_HUE: | |
7197 | + if (ctrl->value > 127) | |
7198 | + dec->hue = 127; | |
7199 | + else if (ctrl->value < -128) | |
7200 | + dec->hue = -128; | |
7201 | + else | |
7202 | + dec->hue = ctrl->value; | |
7203 | + write_reg(client, 0x0d, dec->hue); | |
7204 | + break; | |
7205 | + } | |
7206 | + break; | |
7207 | + } | |
7208 | + case VIDIOC_G_CTRL: | |
7209 | + { | |
7210 | + struct v4l2_control *ctrl = arg; | |
7211 | + | |
7212 | + switch (ctrl->id) { | |
7213 | + case V4L2_CID_BRIGHTNESS: | |
7214 | + ctrl->value = dec->brightness; | |
7215 | + break; | |
7216 | + case V4L2_CID_CONTRAST: | |
7217 | + ctrl->value = dec->contrast; | |
7218 | + break; | |
7219 | + case V4L2_CID_SATURATION: | |
7220 | + ctrl->value = dec->saturation; | |
7221 | + break; | |
7222 | + case V4L2_CID_HUE: | |
7223 | + ctrl->value = dec->hue; | |
7224 | + break; | |
7225 | + } | |
7226 | + break; | |
7227 | + } | |
7228 | + default: | |
7229 | + break; | |
7230 | + } | |
7231 | + return 0; | |
7232 | +} | |
7233 | + | |
7234 | +static struct i2c_driver wis_saa7113_driver; | |
7235 | + | |
7236 | +static struct i2c_client wis_saa7113_client_templ = { | |
7237 | + .name = "SAA7113 (WIS)", | |
7238 | + .driver = &wis_saa7113_driver, | |
7239 | +}; | |
7240 | + | |
7241 | +static int wis_saa7113_detect(struct i2c_adapter *adapter, int addr, int kind) | |
7242 | +{ | |
7243 | + struct i2c_client *client; | |
7244 | + struct wis_saa7113 *dec; | |
7245 | + | |
7246 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
7247 | + return 0; | |
7248 | + | |
7249 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
7250 | + if (client == NULL) | |
7251 | + return -ENOMEM; | |
7252 | + memcpy(client, &wis_saa7113_client_templ, | |
7253 | + sizeof(wis_saa7113_client_templ)); | |
7254 | + client->adapter = adapter; | |
7255 | + client->addr = addr; | |
7256 | + | |
7257 | + dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL); | |
7258 | + if (dec == NULL) { | |
7259 | + kfree(client); | |
7260 | + return -ENOMEM; | |
7261 | + } | |
7262 | + dec->norm = VIDEO_MODE_NTSC; | |
7263 | + dec->brightness = 128; | |
7264 | + dec->contrast = 71; | |
7265 | + dec->saturation = 64; | |
7266 | + dec->hue = 0; | |
7267 | + i2c_set_clientdata(client, dec); | |
7268 | + | |
7269 | + printk(KERN_DEBUG | |
7270 | + "wis-saa7113: initializing SAA7113 at address %d on %s\n", | |
7271 | + addr, adapter->name); | |
7272 | + | |
7273 | + if (write_regs(client, initial_registers) < 0) { | |
7274 | + printk(KERN_ERR | |
7275 | + "wis-saa7113: error initializing SAA7113\n"); | |
7276 | + kfree(client); | |
7277 | + kfree(dec); | |
7278 | + return 0; | |
7279 | + } | |
7280 | + | |
7281 | + i2c_attach_client(client); | |
7282 | + return 0; | |
7283 | +} | |
7284 | + | |
7285 | +static int wis_saa7113_detach(struct i2c_client *client) | |
7286 | +{ | |
7287 | + struct wis_saa7113 *dec = i2c_get_clientdata(client); | |
7288 | + int r; | |
7289 | + | |
7290 | + r = i2c_detach_client(client); | |
7291 | + if (r < 0) | |
7292 | + return r; | |
7293 | + | |
7294 | + kfree(client); | |
7295 | + kfree(dec); | |
7296 | + return 0; | |
7297 | +} | |
7298 | + | |
7299 | +static struct i2c_driver wis_saa7113_driver = { | |
7300 | + .driver = { | |
7301 | + .name = "WIS SAA7113 I2C driver", | |
7302 | + }, | |
7303 | + .id = I2C_DRIVERID_WIS_SAA7113, | |
7304 | + .detach_client = wis_saa7113_detach, | |
7305 | + .command = wis_saa7113_command, | |
7306 | +}; | |
7307 | + | |
7308 | +static int __init wis_saa7113_init(void) | |
7309 | +{ | |
7310 | + int r; | |
7311 | + | |
7312 | + r = i2c_add_driver(&wis_saa7113_driver); | |
7313 | + if (r < 0) | |
7314 | + return r; | |
7315 | + return wis_i2c_add_driver(wis_saa7113_driver.id, wis_saa7113_detect); | |
7316 | +} | |
7317 | + | |
7318 | +static void __exit wis_saa7113_cleanup(void) | |
7319 | +{ | |
7320 | + wis_i2c_del_driver(wis_saa7113_detect); | |
7321 | + i2c_del_driver(&wis_saa7113_driver); | |
7322 | +} | |
7323 | + | |
7324 | +module_init(wis_saa7113_init); | |
7325 | +module_exit(wis_saa7113_cleanup); | |
7326 | + | |
7327 | +MODULE_LICENSE("GPL v2"); | |
7328 | diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c | |
7329 | new file mode 100644 | |
7330 | index 0000000..bd40bf4 | |
7331 | --- /dev/null | |
7332 | +++ b/drivers/staging/go7007/wis-saa7115.c | |
7333 | @@ -0,0 +1,492 @@ | |
7334 | +/* | |
7335 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
7336 | + * | |
7337 | + * This program is free software; you can redistribute it and/or modify | |
7338 | + * it under the terms of the GNU General Public License (Version 2) as | |
7339 | + * published by the Free Software Foundation. | |
7340 | + * | |
7341 | + * This program is distributed in the hope that it will be useful, | |
7342 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
7343 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
7344 | + * GNU General Public License for more details. | |
7345 | + * | |
7346 | + * You should have received a copy of the GNU General Public License | |
7347 | + * along with this program; if not, write to the Free Software Foundation, | |
7348 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
7349 | + */ | |
7350 | + | |
7351 | +#include <linux/module.h> | |
7352 | +#include <linux/init.h> | |
7353 | +#include <linux/version.h> | |
7354 | +#include <linux/i2c.h> | |
7355 | +#include <linux/videodev.h> | |
7356 | +#include <linux/video_decoder.h> | |
7357 | +#include <linux/ioctl.h> | |
7358 | + | |
7359 | +#include "wis-i2c.h" | |
7360 | + | |
7361 | +struct wis_saa7115 { | |
7362 | + int norm; | |
7363 | + int brightness; | |
7364 | + int contrast; | |
7365 | + int saturation; | |
7366 | + int hue; | |
7367 | +}; | |
7368 | + | |
7369 | +static u8 initial_registers[] = | |
7370 | +{ | |
7371 | + 0x01, 0x08, | |
7372 | + 0x02, 0xc0, | |
7373 | + 0x03, 0x20, | |
7374 | + 0x04, 0x80, | |
7375 | + 0x05, 0x80, | |
7376 | + 0x06, 0xeb, | |
7377 | + 0x07, 0xe0, | |
7378 | + 0x08, 0xf0, /* always toggle FID */ | |
7379 | + 0x09, 0x40, | |
7380 | + 0x0a, 0x80, | |
7381 | + 0x0b, 0x40, | |
7382 | + 0x0c, 0x40, | |
7383 | + 0x0d, 0x00, | |
7384 | + 0x0e, 0x03, | |
7385 | + 0x0f, 0x2a, | |
7386 | + 0x10, 0x0e, | |
7387 | + 0x11, 0x00, | |
7388 | + 0x12, 0x8d, | |
7389 | + 0x13, 0x00, | |
7390 | + 0x14, 0x00, | |
7391 | + 0x15, 0x11, | |
7392 | + 0x16, 0x01, | |
7393 | + 0x17, 0xda, | |
7394 | + 0x18, 0x40, | |
7395 | + 0x19, 0x80, | |
7396 | + 0x1a, 0x00, | |
7397 | + 0x1b, 0x42, | |
7398 | + 0x1c, 0xa9, | |
7399 | + 0x30, 0x66, | |
7400 | + 0x31, 0x90, | |
7401 | + 0x32, 0x01, | |
7402 | + 0x34, 0x00, | |
7403 | + 0x35, 0x00, | |
7404 | + 0x36, 0x20, | |
7405 | + 0x38, 0x03, | |
7406 | + 0x39, 0x20, | |
7407 | + 0x3a, 0x88, | |
7408 | + 0x40, 0x00, | |
7409 | + 0x41, 0xff, | |
7410 | + 0x42, 0xff, | |
7411 | + 0x43, 0xff, | |
7412 | + 0x44, 0xff, | |
7413 | + 0x45, 0xff, | |
7414 | + 0x46, 0xff, | |
7415 | + 0x47, 0xff, | |
7416 | + 0x48, 0xff, | |
7417 | + 0x49, 0xff, | |
7418 | + 0x4a, 0xff, | |
7419 | + 0x4b, 0xff, | |
7420 | + 0x4c, 0xff, | |
7421 | + 0x4d, 0xff, | |
7422 | + 0x4e, 0xff, | |
7423 | + 0x4f, 0xff, | |
7424 | + 0x50, 0xff, | |
7425 | + 0x51, 0xff, | |
7426 | + 0x52, 0xff, | |
7427 | + 0x53, 0xff, | |
7428 | + 0x54, 0xf4 /*0xff*/, | |
7429 | + 0x55, 0xff, | |
7430 | + 0x56, 0xff, | |
7431 | + 0x57, 0xff, | |
7432 | + 0x58, 0x40, | |
7433 | + 0x59, 0x47, | |
7434 | + 0x5a, 0x06 /*0x03*/, | |
7435 | + 0x5b, 0x83, | |
7436 | + 0x5d, 0x06, | |
7437 | + 0x5e, 0x00, | |
7438 | + 0x80, 0x30, /* window defined scaler operation, task A and B enabled */ | |
7439 | + 0x81, 0x03, /* use scaler datapath generated V */ | |
7440 | + 0x83, 0x00, | |
7441 | + 0x84, 0x00, | |
7442 | + 0x85, 0x00, | |
7443 | + 0x86, 0x45, | |
7444 | + 0x87, 0x31, | |
7445 | + 0x88, 0xc0, | |
7446 | + 0x90, 0x02, /* task A process top field */ | |
7447 | + 0x91, 0x08, | |
7448 | + 0x92, 0x09, | |
7449 | + 0x93, 0x80, | |
7450 | + 0x94, 0x06, | |
7451 | + 0x95, 0x00, | |
7452 | + 0x96, 0xc0, | |
7453 | + 0x97, 0x02, | |
7454 | + 0x98, 0x12, | |
7455 | + 0x99, 0x00, | |
7456 | + 0x9a, 0xf2, | |
7457 | + 0x9b, 0x00, | |
7458 | + 0x9c, 0xd0, | |
7459 | + 0x9d, 0x02, | |
7460 | + 0x9e, 0xf2, | |
7461 | + 0x9f, 0x00, | |
7462 | + 0xa0, 0x01, | |
7463 | + 0xa1, 0x01, | |
7464 | + 0xa2, 0x01, | |
7465 | + 0xa4, 0x80, | |
7466 | + 0xa5, 0x40, | |
7467 | + 0xa6, 0x40, | |
7468 | + 0xa8, 0x00, | |
7469 | + 0xa9, 0x04, | |
7470 | + 0xaa, 0x00, | |
7471 | + 0xac, 0x00, | |
7472 | + 0xad, 0x02, | |
7473 | + 0xae, 0x00, | |
7474 | + 0xb0, 0x00, | |
7475 | + 0xb1, 0x04, | |
7476 | + 0xb2, 0x00, | |
7477 | + 0xb3, 0x04, | |
7478 | + 0xb4, 0x00, | |
7479 | + 0xb8, 0x00, | |
7480 | + 0xbc, 0x00, | |
7481 | + 0xc0, 0x03, /* task B process bottom field */ | |
7482 | + 0xc1, 0x08, | |
7483 | + 0xc2, 0x09, | |
7484 | + 0xc3, 0x80, | |
7485 | + 0xc4, 0x06, | |
7486 | + 0xc5, 0x00, | |
7487 | + 0xc6, 0xc0, | |
7488 | + 0xc7, 0x02, | |
7489 | + 0xc8, 0x12, | |
7490 | + 0xc9, 0x00, | |
7491 | + 0xca, 0xf2, | |
7492 | + 0xcb, 0x00, | |
7493 | + 0xcc, 0xd0, | |
7494 | + 0xcd, 0x02, | |
7495 | + 0xce, 0xf2, | |
7496 | + 0xcf, 0x00, | |
7497 | + 0xd0, 0x01, | |
7498 | + 0xd1, 0x01, | |
7499 | + 0xd2, 0x01, | |
7500 | + 0xd4, 0x80, | |
7501 | + 0xd5, 0x40, | |
7502 | + 0xd6, 0x40, | |
7503 | + 0xd8, 0x00, | |
7504 | + 0xd9, 0x04, | |
7505 | + 0xda, 0x00, | |
7506 | + 0xdc, 0x00, | |
7507 | + 0xdd, 0x02, | |
7508 | + 0xde, 0x00, | |
7509 | + 0xe0, 0x00, | |
7510 | + 0xe1, 0x04, | |
7511 | + 0xe2, 0x00, | |
7512 | + 0xe3, 0x04, | |
7513 | + 0xe4, 0x00, | |
7514 | + 0xe8, 0x00, | |
7515 | + 0x88, 0xf0, /* End of original static list */ | |
7516 | + 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ | |
7517 | +}; | |
7518 | + | |
7519 | +static int write_reg(struct i2c_client *client, u8 reg, u8 value) | |
7520 | +{ | |
7521 | + return i2c_smbus_write_byte_data(client, reg, value); | |
7522 | +} | |
7523 | + | |
7524 | +static int write_regs(struct i2c_client *client, u8 *regs) | |
7525 | +{ | |
7526 | + int i; | |
7527 | + | |
7528 | + for (i = 0; regs[i] != 0x00; i += 2) | |
7529 | + if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) | |
7530 | + return -1; | |
7531 | + return 0; | |
7532 | +} | |
7533 | + | |
7534 | +static int wis_saa7115_command(struct i2c_client *client, | |
7535 | + unsigned int cmd, void *arg) | |
7536 | +{ | |
7537 | + struct wis_saa7115 *dec = i2c_get_clientdata(client); | |
7538 | + | |
7539 | + switch (cmd) { | |
7540 | + case DECODER_SET_INPUT: | |
7541 | + { | |
7542 | + int *input = arg; | |
7543 | + | |
7544 | + i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); | |
7545 | + i2c_smbus_write_byte_data(client, 0x09, | |
7546 | + *input < 6 ? 0x40 : 0xC0); | |
7547 | + break; | |
7548 | + } | |
7549 | + case DECODER_SET_RESOLUTION: | |
7550 | + { | |
7551 | + struct video_decoder_resolution *res = arg; | |
7552 | + /* Course-grained scaler */ | |
7553 | + int h_integer_scaler = res->width < 704 ? 704 / res->width : 1; | |
7554 | + /* Fine-grained scaler to take care of remainder */ | |
7555 | + int h_scaling_increment = (704 / h_integer_scaler) * | |
7556 | + 1024 / res->width; | |
7557 | + /* Fine-grained scaler only */ | |
7558 | + int v_scaling_increment = (dec->norm == VIDEO_MODE_NTSC ? | |
7559 | + 240 : 288) * 1024 / res->height; | |
7560 | + u8 regs[] = { | |
7561 | + 0x88, 0xc0, | |
7562 | + 0x9c, res->width & 0xff, | |
7563 | + 0x9d, res->width >> 8, | |
7564 | + 0x9e, res->height & 0xff, | |
7565 | + 0x9f, res->height >> 8, | |
7566 | + 0xa0, h_integer_scaler, | |
7567 | + 0xa1, 1, | |
7568 | + 0xa2, 1, | |
7569 | + 0xa8, h_scaling_increment & 0xff, | |
7570 | + 0xa9, h_scaling_increment >> 8, | |
7571 | + 0xac, (h_scaling_increment / 2) & 0xff, | |
7572 | + 0xad, (h_scaling_increment / 2) >> 8, | |
7573 | + 0xb0, v_scaling_increment & 0xff, | |
7574 | + 0xb1, v_scaling_increment >> 8, | |
7575 | + 0xb2, v_scaling_increment & 0xff, | |
7576 | + 0xb3, v_scaling_increment >> 8, | |
7577 | + 0xcc, res->width & 0xff, | |
7578 | + 0xcd, res->width >> 8, | |
7579 | + 0xce, res->height & 0xff, | |
7580 | + 0xcf, res->height >> 8, | |
7581 | + 0xd0, h_integer_scaler, | |
7582 | + 0xd1, 1, | |
7583 | + 0xd2, 1, | |
7584 | + 0xd8, h_scaling_increment & 0xff, | |
7585 | + 0xd9, h_scaling_increment >> 8, | |
7586 | + 0xdc, (h_scaling_increment / 2) & 0xff, | |
7587 | + 0xdd, (h_scaling_increment / 2) >> 8, | |
7588 | + 0xe0, v_scaling_increment & 0xff, | |
7589 | + 0xe1, v_scaling_increment >> 8, | |
7590 | + 0xe2, v_scaling_increment & 0xff, | |
7591 | + 0xe3, v_scaling_increment >> 8, | |
7592 | + 0x88, 0xf0, | |
7593 | + 0, 0, | |
7594 | + }; | |
7595 | + write_regs(client, regs); | |
7596 | + break; | |
7597 | + } | |
7598 | + case DECODER_SET_NORM: | |
7599 | + { | |
7600 | + int *input = arg; | |
7601 | + u8 regs[] = { | |
7602 | + 0x88, 0xc0, | |
7603 | + 0x98, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, | |
7604 | + 0x9a, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, | |
7605 | + 0x9b, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, | |
7606 | + 0xc8, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, | |
7607 | + 0xca, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, | |
7608 | + 0xcb, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, | |
7609 | + 0x88, 0xf0, | |
7610 | + 0x30, *input == VIDEO_MODE_NTSC ? 0x66 : 0x00, | |
7611 | + 0x31, *input == VIDEO_MODE_NTSC ? 0x90 : 0xe0, | |
7612 | + 0, 0, | |
7613 | + }; | |
7614 | + write_regs(client, regs); | |
7615 | + dec->norm = *input; | |
7616 | + break; | |
7617 | + } | |
7618 | + case VIDIOC_QUERYCTRL: | |
7619 | + { | |
7620 | + struct v4l2_queryctrl *ctrl = arg; | |
7621 | + | |
7622 | + switch (ctrl->id) { | |
7623 | + case V4L2_CID_BRIGHTNESS: | |
7624 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7625 | + strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); | |
7626 | + ctrl->minimum = 0; | |
7627 | + ctrl->maximum = 255; | |
7628 | + ctrl->step = 1; | |
7629 | + ctrl->default_value = 128; | |
7630 | + ctrl->flags = 0; | |
7631 | + break; | |
7632 | + case V4L2_CID_CONTRAST: | |
7633 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7634 | + strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); | |
7635 | + ctrl->minimum = 0; | |
7636 | + ctrl->maximum = 127; | |
7637 | + ctrl->step = 1; | |
7638 | + ctrl->default_value = 64; | |
7639 | + ctrl->flags = 0; | |
7640 | + break; | |
7641 | + case V4L2_CID_SATURATION: | |
7642 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7643 | + strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); | |
7644 | + ctrl->minimum = 0; | |
7645 | + ctrl->maximum = 127; | |
7646 | + ctrl->step = 1; | |
7647 | + ctrl->default_value = 64; | |
7648 | + ctrl->flags = 0; | |
7649 | + break; | |
7650 | + case V4L2_CID_HUE: | |
7651 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
7652 | + strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); | |
7653 | + ctrl->minimum = -128; | |
7654 | + ctrl->maximum = 127; | |
7655 | + ctrl->step = 1; | |
7656 | + ctrl->default_value = 0; | |
7657 | + ctrl->flags = 0; | |
7658 | + break; | |
7659 | + } | |
7660 | + break; | |
7661 | + } | |
7662 | + case VIDIOC_S_CTRL: | |
7663 | + { | |
7664 | + struct v4l2_control *ctrl = arg; | |
7665 | + | |
7666 | + switch (ctrl->id) { | |
7667 | + case V4L2_CID_BRIGHTNESS: | |
7668 | + if (ctrl->value > 255) | |
7669 | + dec->brightness = 255; | |
7670 | + else if (ctrl->value < 0) | |
7671 | + dec->brightness = 0; | |
7672 | + else | |
7673 | + dec->brightness = ctrl->value; | |
7674 | + write_reg(client, 0x0a, dec->brightness); | |
7675 | + break; | |
7676 | + case V4L2_CID_CONTRAST: | |
7677 | + if (ctrl->value > 127) | |
7678 | + dec->contrast = 127; | |
7679 | + else if (ctrl->value < 0) | |
7680 | + dec->contrast = 0; | |
7681 | + else | |
7682 | + dec->contrast = ctrl->value; | |
7683 | + write_reg(client, 0x0b, dec->contrast); | |
7684 | + break; | |
7685 | + case V4L2_CID_SATURATION: | |
7686 | + if (ctrl->value > 127) | |
7687 | + dec->saturation = 127; | |
7688 | + else if (ctrl->value < 0) | |
7689 | + dec->saturation = 0; | |
7690 | + else | |
7691 | + dec->saturation = ctrl->value; | |
7692 | + write_reg(client, 0x0c, dec->saturation); | |
7693 | + break; | |
7694 | + case V4L2_CID_HUE: | |
7695 | + if (ctrl->value > 127) | |
7696 | + dec->hue = 127; | |
7697 | + else if (ctrl->value < -128) | |
7698 | + dec->hue = -128; | |
7699 | + else | |
7700 | + dec->hue = ctrl->value; | |
7701 | + write_reg(client, 0x0d, dec->hue); | |
7702 | + break; | |
7703 | + } | |
7704 | + break; | |
7705 | + } | |
7706 | + case VIDIOC_G_CTRL: | |
7707 | + { | |
7708 | + struct v4l2_control *ctrl = arg; | |
7709 | + | |
7710 | + switch (ctrl->id) { | |
7711 | + case V4L2_CID_BRIGHTNESS: | |
7712 | + ctrl->value = dec->brightness; | |
7713 | + break; | |
7714 | + case V4L2_CID_CONTRAST: | |
7715 | + ctrl->value = dec->contrast; | |
7716 | + break; | |
7717 | + case V4L2_CID_SATURATION: | |
7718 | + ctrl->value = dec->saturation; | |
7719 | + break; | |
7720 | + case V4L2_CID_HUE: | |
7721 | + ctrl->value = dec->hue; | |
7722 | + break; | |
7723 | + } | |
7724 | + break; | |
7725 | + } | |
7726 | + default: | |
7727 | + break; | |
7728 | + } | |
7729 | + return 0; | |
7730 | +} | |
7731 | + | |
7732 | +static struct i2c_driver wis_saa7115_driver; | |
7733 | + | |
7734 | +static struct i2c_client wis_saa7115_client_templ = { | |
7735 | + .name = "SAA7115 (WIS)", | |
7736 | + .driver = &wis_saa7115_driver, | |
7737 | +}; | |
7738 | + | |
7739 | +static int wis_saa7115_detect(struct i2c_adapter *adapter, int addr, int kind) | |
7740 | +{ | |
7741 | + struct i2c_client *client; | |
7742 | + struct wis_saa7115 *dec; | |
7743 | + | |
7744 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
7745 | + return 0; | |
7746 | + | |
7747 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
7748 | + if (client == NULL) | |
7749 | + return -ENOMEM; | |
7750 | + memcpy(client, &wis_saa7115_client_templ, | |
7751 | + sizeof(wis_saa7115_client_templ)); | |
7752 | + client->adapter = adapter; | |
7753 | + client->addr = addr; | |
7754 | + | |
7755 | + dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL); | |
7756 | + if (dec == NULL) { | |
7757 | + kfree(client); | |
7758 | + return -ENOMEM; | |
7759 | + } | |
7760 | + dec->norm = VIDEO_MODE_NTSC; | |
7761 | + dec->brightness = 128; | |
7762 | + dec->contrast = 64; | |
7763 | + dec->saturation = 64; | |
7764 | + dec->hue = 0; | |
7765 | + i2c_set_clientdata(client, dec); | |
7766 | + | |
7767 | + printk(KERN_DEBUG | |
7768 | + "wis-saa7115: initializing SAA7115 at address %d on %s\n", | |
7769 | + addr, adapter->name); | |
7770 | + | |
7771 | + if (write_regs(client, initial_registers) < 0) { | |
7772 | + printk(KERN_ERR | |
7773 | + "wis-saa7115: error initializing SAA7115\n"); | |
7774 | + kfree(client); | |
7775 | + kfree(dec); | |
7776 | + return 0; | |
7777 | + } | |
7778 | + | |
7779 | + i2c_attach_client(client); | |
7780 | + return 0; | |
7781 | +} | |
7782 | + | |
7783 | +static int wis_saa7115_detach(struct i2c_client *client) | |
7784 | +{ | |
7785 | + struct wis_saa7115 *dec = i2c_get_clientdata(client); | |
7786 | + int r; | |
7787 | + | |
7788 | + r = i2c_detach_client(client); | |
7789 | + if (r < 0) | |
7790 | + return r; | |
7791 | + | |
7792 | + kfree(client); | |
7793 | + kfree(dec); | |
7794 | + return 0; | |
7795 | +} | |
7796 | + | |
7797 | +static struct i2c_driver wis_saa7115_driver = { | |
7798 | + .driver = { | |
7799 | + .name = "WIS SAA7115 I2C driver", | |
7800 | + }, | |
7801 | + .id = I2C_DRIVERID_WIS_SAA7115, | |
7802 | + .detach_client = wis_saa7115_detach, | |
7803 | + .command = wis_saa7115_command, | |
7804 | +}; | |
7805 | + | |
7806 | +static int __init wis_saa7115_init(void) | |
7807 | +{ | |
7808 | + int r; | |
7809 | + | |
7810 | + r = i2c_add_driver(&wis_saa7115_driver); | |
7811 | + if (r < 0) | |
7812 | + return r; | |
7813 | + return wis_i2c_add_driver(wis_saa7115_driver.id, wis_saa7115_detect); | |
7814 | +} | |
7815 | + | |
7816 | +static void __exit wis_saa7115_cleanup(void) | |
7817 | +{ | |
7818 | + wis_i2c_del_driver(wis_saa7115_detect); | |
7819 | + i2c_del_driver(&wis_saa7115_driver); | |
7820 | +} | |
7821 | + | |
7822 | +module_init(wis_saa7115_init); | |
7823 | +module_exit(wis_saa7115_cleanup); | |
7824 | + | |
7825 | +MODULE_LICENSE("GPL v2"); | |
7826 | diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c | |
7827 | new file mode 100644 | |
7828 | index 0000000..82e66d6 | |
7829 | --- /dev/null | |
7830 | +++ b/drivers/staging/go7007/wis-sony-tuner.c | |
7831 | @@ -0,0 +1,741 @@ | |
7832 | +/* | |
7833 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
7834 | + * | |
7835 | + * This program is free software; you can redistribute it and/or modify | |
7836 | + * it under the terms of the GNU General Public License (Version 2) as | |
7837 | + * published by the Free Software Foundation. | |
7838 | + * | |
7839 | + * This program is distributed in the hope that it will be useful, | |
7840 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
7841 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
7842 | + * GNU General Public License for more details. | |
7843 | + * | |
7844 | + * You should have received a copy of the GNU General Public License | |
7845 | + * along with this program; if not, write to the Free Software Foundation, | |
7846 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
7847 | + */ | |
7848 | + | |
7849 | +#include <linux/module.h> | |
7850 | +#include <linux/init.h> | |
7851 | +#include <linux/version.h> | |
7852 | +#include <linux/i2c.h> | |
7853 | +#include <linux/videodev.h> | |
7854 | +#include <media/tuner.h> | |
7855 | +#include <media/v4l2-common.h> | |
7856 | + | |
7857 | +#include "wis-i2c.h" | |
7858 | + | |
7859 | +/* #define MPX_DEBUG */ | |
7860 | + | |
7861 | +/* AS(IF/MPX) pin: LOW HIGH/OPEN | |
7862 | + * IF/MPX address: 0x42/0x40 0x43/0x44 | |
7863 | + */ | |
7864 | +#define IF_I2C_ADDR 0x43 | |
7865 | +#define MPX_I2C_ADDR 0x44 | |
7866 | + | |
7867 | +static v4l2_std_id force_band; | |
7868 | +static char force_band_str[] = "-"; | |
7869 | +module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644); | |
7870 | +static int force_mpx_mode = -1; | |
7871 | +module_param(force_mpx_mode, int, 0644); | |
7872 | + | |
7873 | +/* Store tuner info in the same format as tuner.c, so maybe we can put the | |
7874 | + * Sony tuner support in there. */ | |
7875 | +struct sony_tunertype { | |
7876 | + char *name; | |
7877 | + unsigned char Vendor; /* unused here */ | |
7878 | + unsigned char Type; /* unused here */ | |
7879 | + | |
7880 | + unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ | |
7881 | + unsigned short thresh2; /* band switch VHF_HI <=> UHF */ | |
7882 | + unsigned char VHF_L; | |
7883 | + unsigned char VHF_H; | |
7884 | + unsigned char UHF; | |
7885 | + unsigned char config; | |
7886 | + unsigned short IFPCoff; | |
7887 | +}; | |
7888 | + | |
7889 | +/* This array is indexed by (tuner_type - 200) */ | |
7890 | +static struct sony_tunertype sony_tuners[] = { | |
7891 | + { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0, | |
7892 | + 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623}, | |
7893 | + { "Sony NTSC_JP (BTF-PK467Z)", 0, 0, | |
7894 | + 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940}, | |
7895 | + { "Sony NTSC (BTF-PB463Z)", 0, 0, | |
7896 | + 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732}, | |
7897 | +}; | |
7898 | + | |
7899 | +struct wis_sony_tuner { | |
7900 | + int type; | |
7901 | + v4l2_std_id std; | |
7902 | + unsigned int freq; | |
7903 | + int mpxmode; | |
7904 | + u32 audmode; | |
7905 | +}; | |
7906 | + | |
7907 | +/* Basically the same as default_set_tv_freq() in tuner.c */ | |
7908 | +static int set_freq(struct i2c_client *client, int freq) | |
7909 | +{ | |
7910 | + struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
7911 | + char *band_name; | |
7912 | + int n; | |
7913 | + int band_select; | |
7914 | + struct sony_tunertype *tun; | |
7915 | + u8 buffer[4]; | |
7916 | + | |
7917 | + tun = &sony_tuners[t->type - 200]; | |
7918 | + if (freq < tun->thresh1) { | |
7919 | + band_name = "VHF_L"; | |
7920 | + band_select = tun->VHF_L; | |
7921 | + } else if (freq < tun->thresh2) { | |
7922 | + band_name = "VHF_H"; | |
7923 | + band_select = tun->VHF_H; | |
7924 | + } else { | |
7925 | + band_name = "UHF"; | |
7926 | + band_select = tun->UHF; | |
7927 | + } | |
7928 | + printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n", | |
7929 | + freq / 16, (freq % 16) * 625, band_name); | |
7930 | + n = freq + tun->IFPCoff; | |
7931 | + | |
7932 | + buffer[0] = n >> 8; | |
7933 | + buffer[1] = n & 0xff; | |
7934 | + buffer[2] = tun->config; | |
7935 | + buffer[3] = band_select; | |
7936 | + i2c_master_send(client, buffer, 4); | |
7937 | + | |
7938 | + return 0; | |
7939 | +} | |
7940 | + | |
7941 | +static int mpx_write(struct i2c_client *client, int dev, int addr, int val) | |
7942 | +{ | |
7943 | + u8 buffer[5]; | |
7944 | + struct i2c_msg msg; | |
7945 | + | |
7946 | + buffer[0] = dev; | |
7947 | + buffer[1] = addr >> 8; | |
7948 | + buffer[2] = addr & 0xff; | |
7949 | + buffer[3] = val >> 8; | |
7950 | + buffer[4] = val & 0xff; | |
7951 | + msg.addr = MPX_I2C_ADDR; | |
7952 | + msg.flags = 0; | |
7953 | + msg.len = 5; | |
7954 | + msg.buf = buffer; | |
7955 | + i2c_transfer(client->adapter, &msg, 1); | |
7956 | + return 0; | |
7957 | +} | |
7958 | + | |
7959 | +/* | |
7960 | + * MPX register values for the BTF-PG472Z: | |
7961 | + * | |
7962 | + * FM_ NICAM_ SCART_ | |
7963 | + * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME | |
7964 | + * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000 | |
7965 | + * --------------------------------------------------------------- | |
7966 | + * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500 | |
7967 | + * | |
7968 | + * B/G | |
7969 | + * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500 | |
7970 | + * A2 1003 0020 0100 2601 5000 XXXX 0003 7500 | |
7971 | + * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500 | |
7972 | + * | |
7973 | + * I | |
7974 | + * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500 | |
7975 | + * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500 | |
7976 | + * | |
7977 | + * D/K | |
7978 | + * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500 | |
7979 | + * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500 | |
7980 | + * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500 | |
7981 | + * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500 | |
7982 | + * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500 | |
7983 | + * | |
7984 | + * L/L' | |
7985 | + * Mono 0003 0200 0100 7C03 5000 2200 0009 7500 | |
7986 | + * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500 | |
7987 | + * | |
7988 | + * M | |
7989 | + * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500 | |
7990 | + * | |
7991 | + * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX. | |
7992 | + * | |
7993 | + * Bilingual selection in A2/NICAM: | |
7994 | + * | |
7995 | + * High byte of SOURCE Left chan Right chan | |
7996 | + * 0x01 MAIN SUB | |
7997 | + * 0x03 MAIN MAIN | |
7998 | + * 0x04 SUB SUB | |
7999 | + * | |
8000 | + * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or | |
8001 | + * 0x00 (all other bands). Force mono in A2 with FMONO_A2: | |
8002 | + * | |
8003 | + * FMONO_A2 | |
8004 | + * 10/0022 | |
8005 | + * -------- | |
8006 | + * Forced mono ON 07F0 | |
8007 | + * Forced mono OFF 0190 | |
8008 | + */ | |
8009 | + | |
8010 | +static struct { | |
8011 | + enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; | |
8012 | + u16 modus; | |
8013 | + u16 source; | |
8014 | + u16 acb; | |
8015 | + u16 fm_prescale; | |
8016 | + u16 nicam_prescale; | |
8017 | + u16 scart_prescale; | |
8018 | + u16 system; | |
8019 | + u16 volume; | |
8020 | +} mpx_audio_modes[] = { | |
8021 | + /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
8022 | + 0x5000, 0x0000, 0x0001, 0x7500 }, | |
8023 | + /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
8024 | + 0x5000, 0x0000, 0x0003, 0x7500 }, | |
8025 | + /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
8026 | + 0x5000, 0x0000, 0x0003, 0x7500 }, | |
8027 | + /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
8028 | + 0x5000, 0x0000, 0x0008, 0x7500 }, | |
8029 | + /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
8030 | + 0x7900, 0x0000, 0x000A, 0x7500 }, | |
8031 | + /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
8032 | + 0x7900, 0x0000, 0x000A, 0x7500 }, | |
8033 | + /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
8034 | + 0x5000, 0x0000, 0x0004, 0x7500 }, | |
8035 | + /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
8036 | + 0x5000, 0x0000, 0x0004, 0x7500 }, | |
8037 | + /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
8038 | + 0x5000, 0x0000, 0x0005, 0x7500 }, | |
8039 | + /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
8040 | + 0x5000, 0x0000, 0x0007, 0x7500 }, | |
8041 | + /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
8042 | + 0x5000, 0x0000, 0x000B, 0x7500 }, | |
8043 | + /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, | |
8044 | + 0x5000, 0x2200, 0x0009, 0x7500 }, | |
8045 | + /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, | |
8046 | + 0x5000, 0x0000, 0x0009, 0x7500 }, | |
8047 | +}; | |
8048 | + | |
8049 | +#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) | |
8050 | + | |
8051 | +static int mpx_setup(struct i2c_client *client) | |
8052 | +{ | |
8053 | + struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
8054 | + u16 source = 0; | |
8055 | + u8 buffer[3]; | |
8056 | + struct i2c_msg msg; | |
8057 | + | |
8058 | + /* reset MPX */ | |
8059 | + buffer[0] = 0x00; | |
8060 | + buffer[1] = 0x80; | |
8061 | + buffer[2] = 0x00; | |
8062 | + msg.addr = MPX_I2C_ADDR; | |
8063 | + msg.flags = 0; | |
8064 | + msg.len = 3; | |
8065 | + msg.buf = buffer; | |
8066 | + i2c_transfer(client->adapter, &msg, 1); | |
8067 | + buffer[1] = 0x00; | |
8068 | + i2c_transfer(client->adapter, &msg, 1); | |
8069 | + | |
8070 | + if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { | |
8071 | + switch (t->audmode) { | |
8072 | + case V4L2_TUNER_MODE_MONO: | |
8073 | + switch (mpx_audio_modes[t->mpxmode].audio_mode) { | |
8074 | + case AUD_A2: | |
8075 | + source = mpx_audio_modes[t->mpxmode].source; | |
8076 | + break; | |
8077 | + case AUD_NICAM: | |
8078 | + source = 0x0000; | |
8079 | + break; | |
8080 | + case AUD_NICAM_L: | |
8081 | + source = 0x0200; | |
8082 | + break; | |
8083 | + default: | |
8084 | + break; | |
8085 | + } | |
8086 | + break; | |
8087 | + case V4L2_TUNER_MODE_STEREO: | |
8088 | + source = mpx_audio_modes[t->mpxmode].source; | |
8089 | + break; | |
8090 | + case V4L2_TUNER_MODE_LANG1: | |
8091 | + source = 0x0300; | |
8092 | + break; | |
8093 | + case V4L2_TUNER_MODE_LANG2: | |
8094 | + source = 0x0400; | |
8095 | + break; | |
8096 | + } | |
8097 | + source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; | |
8098 | + } else | |
8099 | + source = mpx_audio_modes[t->mpxmode].source; | |
8100 | + | |
8101 | + mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); | |
8102 | + mpx_write(client, 0x12, 0x0008, source); | |
8103 | + mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); | |
8104 | + mpx_write(client, 0x12, 0x000e, | |
8105 | + mpx_audio_modes[t->mpxmode].fm_prescale); | |
8106 | + mpx_write(client, 0x12, 0x0010, | |
8107 | + mpx_audio_modes[t->mpxmode].nicam_prescale); | |
8108 | + mpx_write(client, 0x12, 0x000d, | |
8109 | + mpx_audio_modes[t->mpxmode].scart_prescale); | |
8110 | + mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); | |
8111 | + mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); | |
8112 | + if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2) | |
8113 | + mpx_write(client, 0x10, 0x0022, | |
8114 | + t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); | |
8115 | + | |
8116 | +#ifdef MPX_DEBUG | |
8117 | + { | |
8118 | + u8 buf1[3], buf2[2]; | |
8119 | + struct i2c_msg msgs[2]; | |
8120 | + | |
8121 | + printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x " | |
8122 | + "%04x %04x %04x %04x %04x %04x\n", | |
8123 | + mpx_audio_modes[t->mpxmode].modus, | |
8124 | + source, | |
8125 | + mpx_audio_modes[t->mpxmode].acb, | |
8126 | + mpx_audio_modes[t->mpxmode].fm_prescale, | |
8127 | + mpx_audio_modes[t->mpxmode].nicam_prescale, | |
8128 | + mpx_audio_modes[t->mpxmode].scart_prescale, | |
8129 | + mpx_audio_modes[t->mpxmode].system, | |
8130 | + mpx_audio_modes[t->mpxmode].volume); | |
8131 | + buf1[0] = 0x11; | |
8132 | + buf1[1] = 0x00; | |
8133 | + buf1[2] = 0x7e; | |
8134 | + msgs[0].addr = MPX_I2C_ADDR; | |
8135 | + msgs[0].flags = 0; | |
8136 | + msgs[0].len = 3; | |
8137 | + msgs[0].buf = buf1; | |
8138 | + msgs[1].addr = MPX_I2C_ADDR; | |
8139 | + msgs[1].flags = I2C_M_RD; | |
8140 | + msgs[1].len = 2; | |
8141 | + msgs[1].buf = buf2; | |
8142 | + i2c_transfer(client->adapter, msgs, 2); | |
8143 | + printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n", | |
8144 | + buf2[0], buf2[1]); | |
8145 | + buf1[0] = 0x11; | |
8146 | + buf1[1] = 0x02; | |
8147 | + buf1[2] = 0x00; | |
8148 | + i2c_transfer(client->adapter, msgs, 2); | |
8149 | + printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n", | |
8150 | + buf2[0], buf2[1]); | |
8151 | + } | |
8152 | +#endif | |
8153 | + return 0; | |
8154 | +} | |
8155 | + | |
8156 | +/* | |
8157 | + * IF configuration values for the BTF-PG472Z: | |
8158 | + * | |
8159 | + * B/G: 0x94 0x70 0x49 | |
8160 | + * I: 0x14 0x70 0x4a | |
8161 | + * D/K: 0x14 0x70 0x4b | |
8162 | + * L: 0x04 0x70 0x4b | |
8163 | + * L': 0x44 0x70 0x53 | |
8164 | + * M: 0x50 0x30 0x4c | |
8165 | + */ | |
8166 | + | |
8167 | +static int set_if(struct i2c_client *client) | |
8168 | +{ | |
8169 | + struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
8170 | + u8 buffer[4]; | |
8171 | + struct i2c_msg msg; | |
8172 | + int default_mpx_mode = 0; | |
8173 | + | |
8174 | + /* configure IF */ | |
8175 | + buffer[0] = 0; | |
8176 | + if (t->std & V4L2_STD_PAL_BG) { | |
8177 | + buffer[1] = 0x94; | |
8178 | + buffer[2] = 0x70; | |
8179 | + buffer[3] = 0x49; | |
8180 | + default_mpx_mode = 1; | |
8181 | + } else if (t->std & V4L2_STD_PAL_I) { | |
8182 | + buffer[1] = 0x14; | |
8183 | + buffer[2] = 0x70; | |
8184 | + buffer[3] = 0x4a; | |
8185 | + default_mpx_mode = 4; | |
8186 | + } else if (t->std & V4L2_STD_PAL_DK) { | |
8187 | + buffer[1] = 0x14; | |
8188 | + buffer[2] = 0x70; | |
8189 | + buffer[3] = 0x4b; | |
8190 | + default_mpx_mode = 6; | |
8191 | + } else if (t->std & V4L2_STD_SECAM_L) { | |
8192 | + buffer[1] = 0x04; | |
8193 | + buffer[2] = 0x70; | |
8194 | + buffer[3] = 0x4b; | |
8195 | + default_mpx_mode = 11; | |
8196 | + } | |
8197 | + msg.addr = IF_I2C_ADDR; | |
8198 | + msg.flags = 0; | |
8199 | + msg.len = 4; | |
8200 | + msg.buf = buffer; | |
8201 | + i2c_transfer(client->adapter, &msg, 1); | |
8202 | + | |
8203 | + /* Select MPX mode if not forced by the user */ | |
8204 | + if (force_mpx_mode >= 0 || force_mpx_mode < MPX_NUM_MODES) | |
8205 | + t->mpxmode = force_mpx_mode; | |
8206 | + else | |
8207 | + t->mpxmode = default_mpx_mode; | |
8208 | + printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n", | |
8209 | + t->mpxmode); | |
8210 | + mpx_setup(client); | |
8211 | + | |
8212 | + return 0; | |
8213 | +} | |
8214 | + | |
8215 | +static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |
8216 | +{ | |
8217 | + struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
8218 | + | |
8219 | + switch (cmd) { | |
8220 | +#ifdef TUNER_SET_TYPE_ADDR | |
8221 | + case TUNER_SET_TYPE_ADDR: | |
8222 | + { | |
8223 | + struct tuner_setup *tun_setup = arg; | |
8224 | + int *type = &tun_setup->type; | |
8225 | +#else | |
8226 | + case TUNER_SET_TYPE: | |
8227 | + { | |
8228 | + int *type = arg; | |
8229 | +#endif | |
8230 | + | |
8231 | + if (t->type >= 0) { | |
8232 | + if (t->type != *type) | |
8233 | + printk(KERN_ERR "wis-sony-tuner: type already " | |
8234 | + "set to %d, ignoring request for %d\n", | |
8235 | + t->type, *type); | |
8236 | + break; | |
8237 | + } | |
8238 | + t->type = *type; | |
8239 | + switch (t->type) { | |
8240 | + case TUNER_SONY_BTF_PG472Z: | |
8241 | + switch (force_band_str[0]) { | |
8242 | + case 'b': | |
8243 | + case 'B': | |
8244 | + case 'g': | |
8245 | + case 'G': | |
8246 | + printk(KERN_INFO "wis-sony-tuner: forcing " | |
8247 | + "tuner to PAL-B/G bands\n"); | |
8248 | + force_band = V4L2_STD_PAL_BG; | |
8249 | + break; | |
8250 | + case 'i': | |
8251 | + case 'I': | |
8252 | + printk(KERN_INFO "wis-sony-tuner: forcing " | |
8253 | + "tuner to PAL-I band\n"); | |
8254 | + force_band = V4L2_STD_PAL_I; | |
8255 | + break; | |
8256 | + case 'd': | |
8257 | + case 'D': | |
8258 | + case 'k': | |
8259 | + case 'K': | |
8260 | + printk(KERN_INFO "wis-sony-tuner: forcing " | |
8261 | + "tuner to PAL-D/K bands\n"); | |
8262 | + force_band = V4L2_STD_PAL_I; | |
8263 | + break; | |
8264 | + case 'l': | |
8265 | + case 'L': | |
8266 | + printk(KERN_INFO "wis-sony-tuner: forcing " | |
8267 | + "tuner to SECAM-L band\n"); | |
8268 | + force_band = V4L2_STD_SECAM_L; | |
8269 | + break; | |
8270 | + default: | |
8271 | + force_band = 0; | |
8272 | + break; | |
8273 | + } | |
8274 | + if (force_band) | |
8275 | + t->std = force_band; | |
8276 | + else | |
8277 | + t->std = V4L2_STD_PAL_BG; | |
8278 | + set_if(client); | |
8279 | + break; | |
8280 | + case TUNER_SONY_BTF_PK467Z: | |
8281 | + t->std = V4L2_STD_NTSC_M_JP; | |
8282 | + break; | |
8283 | + case TUNER_SONY_BTF_PB463Z: | |
8284 | + t->std = V4L2_STD_NTSC_M; | |
8285 | + break; | |
8286 | + default: | |
8287 | + printk(KERN_ERR "wis-sony-tuner: tuner type %d is not " | |
8288 | + "supported by this module\n", *type); | |
8289 | + break; | |
8290 | + } | |
8291 | + if (type >= 0) | |
8292 | + printk(KERN_INFO | |
8293 | + "wis-sony-tuner: type set to %d (%s)\n", | |
8294 | + t->type, sony_tuners[t->type - 200].name); | |
8295 | + break; | |
8296 | + } | |
8297 | + case VIDIOC_G_FREQUENCY: | |
8298 | + { | |
8299 | + struct v4l2_frequency *f = arg; | |
8300 | + | |
8301 | + f->frequency = t->freq; | |
8302 | + break; | |
8303 | + } | |
8304 | + case VIDIOC_S_FREQUENCY: | |
8305 | + { | |
8306 | + struct v4l2_frequency *f = arg; | |
8307 | + | |
8308 | + t->freq = f->frequency; | |
8309 | + set_freq(client, t->freq); | |
8310 | + break; | |
8311 | + } | |
8312 | + case VIDIOC_ENUMSTD: | |
8313 | + { | |
8314 | + struct v4l2_standard *std = arg; | |
8315 | + | |
8316 | + switch (t->type) { | |
8317 | + case TUNER_SONY_BTF_PG472Z: | |
8318 | + switch (std->index) { | |
8319 | + case 0: | |
8320 | + v4l2_video_std_construct(std, | |
8321 | + V4L2_STD_PAL_BG, "PAL-B/G"); | |
8322 | + break; | |
8323 | + case 1: | |
8324 | + v4l2_video_std_construct(std, | |
8325 | + V4L2_STD_PAL_I, "PAL-I"); | |
8326 | + break; | |
8327 | + case 2: | |
8328 | + v4l2_video_std_construct(std, | |
8329 | + V4L2_STD_PAL_DK, "PAL-D/K"); | |
8330 | + break; | |
8331 | + case 3: | |
8332 | + v4l2_video_std_construct(std, | |
8333 | + V4L2_STD_SECAM_L, "SECAM-L"); | |
8334 | + break; | |
8335 | + default: | |
8336 | + std->id = 0; /* hack to indicate EINVAL */ | |
8337 | + break; | |
8338 | + } | |
8339 | + break; | |
8340 | + case TUNER_SONY_BTF_PK467Z: | |
8341 | + if (std->index != 0) { | |
8342 | + std->id = 0; /* hack to indicate EINVAL */ | |
8343 | + break; | |
8344 | + } | |
8345 | + v4l2_video_std_construct(std, | |
8346 | + V4L2_STD_NTSC_M_JP, "NTSC-J"); | |
8347 | + break; | |
8348 | + case TUNER_SONY_BTF_PB463Z: | |
8349 | + if (std->index != 0) { | |
8350 | + std->id = 0; /* hack to indicate EINVAL */ | |
8351 | + break; | |
8352 | + } | |
8353 | + v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); | |
8354 | + break; | |
8355 | + } | |
8356 | + break; | |
8357 | + } | |
8358 | + case VIDIOC_G_STD: | |
8359 | + { | |
8360 | + v4l2_std_id *std = arg; | |
8361 | + | |
8362 | + *std = t->std; | |
8363 | + break; | |
8364 | + } | |
8365 | + case VIDIOC_S_STD: | |
8366 | + { | |
8367 | + v4l2_std_id *std = arg; | |
8368 | + v4l2_std_id old = t->std; | |
8369 | + | |
8370 | + switch (t->type) { | |
8371 | + case TUNER_SONY_BTF_PG472Z: | |
8372 | + if (force_band && (*std & force_band) != *std && | |
8373 | + *std != V4L2_STD_PAL && | |
8374 | + *std != V4L2_STD_SECAM) { | |
8375 | + printk(KERN_DEBUG "wis-sony-tuner: ignoring " | |
8376 | + "requested TV standard in " | |
8377 | + "favor of force_band value\n"); | |
8378 | + t->std = force_band; | |
8379 | + } else if (*std & V4L2_STD_PAL_BG) { /* default */ | |
8380 | + t->std = V4L2_STD_PAL_BG; | |
8381 | + } else if (*std & V4L2_STD_PAL_I) { | |
8382 | + t->std = V4L2_STD_PAL_I; | |
8383 | + } else if (*std & V4L2_STD_PAL_DK) { | |
8384 | + t->std = V4L2_STD_PAL_DK; | |
8385 | + } else if (*std & V4L2_STD_SECAM_L) { | |
8386 | + t->std = V4L2_STD_SECAM_L; | |
8387 | + } else { | |
8388 | + printk(KERN_ERR "wis-sony-tuner: TV standard " | |
8389 | + "not supported\n"); | |
8390 | + *std = 0; /* hack to indicate EINVAL */ | |
8391 | + break; | |
8392 | + } | |
8393 | + if (old != t->std) | |
8394 | + set_if(client); | |
8395 | + break; | |
8396 | + case TUNER_SONY_BTF_PK467Z: | |
8397 | + if (!(*std & V4L2_STD_NTSC_M_JP)) { | |
8398 | + printk(KERN_ERR "wis-sony-tuner: TV standard " | |
8399 | + "not supported\n"); | |
8400 | + *std = 0; /* hack to indicate EINVAL */ | |
8401 | + } | |
8402 | + break; | |
8403 | + case TUNER_SONY_BTF_PB463Z: | |
8404 | + if (!(*std & V4L2_STD_NTSC_M)) { | |
8405 | + printk(KERN_ERR "wis-sony-tuner: TV standard " | |
8406 | + "not supported\n"); | |
8407 | + *std = 0; /* hack to indicate EINVAL */ | |
8408 | + } | |
8409 | + break; | |
8410 | + } | |
8411 | + break; | |
8412 | + } | |
8413 | + case VIDIOC_QUERYSTD: | |
8414 | + { | |
8415 | + v4l2_std_id *std = arg; | |
8416 | + | |
8417 | + switch (t->type) { | |
8418 | + case TUNER_SONY_BTF_PG472Z: | |
8419 | + if (force_band) | |
8420 | + *std = force_band; | |
8421 | + else | |
8422 | + *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | | |
8423 | + V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; | |
8424 | + break; | |
8425 | + case TUNER_SONY_BTF_PK467Z: | |
8426 | + *std = V4L2_STD_NTSC_M_JP; | |
8427 | + break; | |
8428 | + case TUNER_SONY_BTF_PB463Z: | |
8429 | + *std = V4L2_STD_NTSC_M; | |
8430 | + break; | |
8431 | + } | |
8432 | + break; | |
8433 | + } | |
8434 | + case VIDIOC_G_TUNER: | |
8435 | + { | |
8436 | + struct v4l2_tuner *tun = arg; | |
8437 | + | |
8438 | + memset(t, 0, sizeof(*tun)); | |
8439 | + strcpy(tun->name, "Television"); | |
8440 | + tun->type = V4L2_TUNER_ANALOG_TV; | |
8441 | + tun->rangelow = 0UL; /* does anything use these? */ | |
8442 | + tun->rangehigh = 0xffffffffUL; | |
8443 | + switch (t->type) { | |
8444 | + case TUNER_SONY_BTF_PG472Z: | |
8445 | + tun->capability = V4L2_TUNER_CAP_NORM | | |
8446 | + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | |
8447 | + V4L2_TUNER_CAP_LANG2; | |
8448 | + tun->rxsubchans = V4L2_TUNER_SUB_MONO | | |
8449 | + V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | | |
8450 | + V4L2_TUNER_SUB_LANG2; | |
8451 | + break; | |
8452 | + case TUNER_SONY_BTF_PK467Z: | |
8453 | + case TUNER_SONY_BTF_PB463Z: | |
8454 | + tun->capability = V4L2_TUNER_CAP_STEREO; | |
8455 | + tun->rxsubchans = V4L2_TUNER_SUB_MONO | | |
8456 | + V4L2_TUNER_SUB_STEREO; | |
8457 | + break; | |
8458 | + } | |
8459 | + tun->audmode = t->audmode; | |
8460 | + return 0; | |
8461 | + } | |
8462 | + case VIDIOC_S_TUNER: | |
8463 | + { | |
8464 | + struct v4l2_tuner *tun = arg; | |
8465 | + | |
8466 | + switch (t->type) { | |
8467 | + case TUNER_SONY_BTF_PG472Z: | |
8468 | + if (tun->audmode != t->audmode) { | |
8469 | + t->audmode = tun->audmode; | |
8470 | + mpx_setup(client); | |
8471 | + } | |
8472 | + break; | |
8473 | + case TUNER_SONY_BTF_PK467Z: | |
8474 | + case TUNER_SONY_BTF_PB463Z: | |
8475 | + break; | |
8476 | + } | |
8477 | + return 0; | |
8478 | + } | |
8479 | + default: | |
8480 | + break; | |
8481 | + } | |
8482 | + return 0; | |
8483 | +} | |
8484 | + | |
8485 | +static struct i2c_driver wis_sony_tuner_driver; | |
8486 | + | |
8487 | +static struct i2c_client wis_sony_tuner_client_templ = { | |
8488 | + .name = "Sony TV Tuner (WIS)", | |
8489 | + .driver = &wis_sony_tuner_driver, | |
8490 | +}; | |
8491 | + | |
8492 | +static int wis_sony_tuner_detect(struct i2c_adapter *adapter, | |
8493 | + int addr, int kind) | |
8494 | +{ | |
8495 | + struct i2c_client *client; | |
8496 | + struct wis_sony_tuner *t; | |
8497 | + | |
8498 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) | |
8499 | + return 0; | |
8500 | + | |
8501 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
8502 | + if (client == NULL) | |
8503 | + return -ENOMEM; | |
8504 | + memcpy(client, &wis_sony_tuner_client_templ, | |
8505 | + sizeof(wis_sony_tuner_client_templ)); | |
8506 | + client->adapter = adapter; | |
8507 | + client->addr = addr; | |
8508 | + | |
8509 | + t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); | |
8510 | + if (t == NULL) { | |
8511 | + kfree(client); | |
8512 | + return -ENOMEM; | |
8513 | + } | |
8514 | + t->type = -1; | |
8515 | + t->freq = 0; | |
8516 | + t->mpxmode = 0; | |
8517 | + t->audmode = V4L2_TUNER_MODE_STEREO; | |
8518 | + i2c_set_clientdata(client, t); | |
8519 | + | |
8520 | + printk(KERN_DEBUG | |
8521 | + "wis-sony-tuner: initializing tuner at address %d on %s\n", | |
8522 | + addr, adapter->name); | |
8523 | + | |
8524 | + i2c_attach_client(client); | |
8525 | + | |
8526 | + return 0; | |
8527 | +} | |
8528 | + | |
8529 | +static int wis_sony_tuner_detach(struct i2c_client *client) | |
8530 | +{ | |
8531 | + struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
8532 | + int r; | |
8533 | + | |
8534 | + r = i2c_detach_client(client); | |
8535 | + if (r < 0) | |
8536 | + return r; | |
8537 | + | |
8538 | + kfree(t); | |
8539 | + kfree(client); | |
8540 | + return 0; | |
8541 | +} | |
8542 | + | |
8543 | +static struct i2c_driver wis_sony_tuner_driver = { | |
8544 | + .driver = { | |
8545 | + .name = "WIS Sony TV Tuner I2C driver", | |
8546 | + }, | |
8547 | + .id = I2C_DRIVERID_WIS_SONY_TUNER, | |
8548 | + .detach_client = wis_sony_tuner_detach, | |
8549 | + .command = tuner_command, | |
8550 | +}; | |
8551 | + | |
8552 | +static int __init wis_sony_tuner_init(void) | |
8553 | +{ | |
8554 | + int r; | |
8555 | + | |
8556 | + r = i2c_add_driver(&wis_sony_tuner_driver); | |
8557 | + if (r < 0) | |
8558 | + return r; | |
8559 | + return wis_i2c_add_driver(wis_sony_tuner_driver.id, | |
8560 | + wis_sony_tuner_detect); | |
8561 | +} | |
8562 | + | |
8563 | +static void __exit wis_sony_tuner_cleanup(void) | |
8564 | +{ | |
8565 | + wis_i2c_del_driver(wis_sony_tuner_detect); | |
8566 | + i2c_del_driver(&wis_sony_tuner_driver); | |
8567 | +} | |
8568 | + | |
8569 | +module_init(wis_sony_tuner_init); | |
8570 | +module_exit(wis_sony_tuner_cleanup); | |
8571 | + | |
8572 | +MODULE_LICENSE("GPL v2"); | |
8573 | diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c | |
8574 | new file mode 100644 | |
8575 | index 0000000..69ed7bf | |
8576 | --- /dev/null | |
8577 | +++ b/drivers/staging/go7007/wis-tw2804.c | |
8578 | @@ -0,0 +1,381 @@ | |
8579 | +/* | |
8580 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
8581 | + * | |
8582 | + * This program is free software; you can redistribute it and/or modify | |
8583 | + * it under the terms of the GNU General Public License (Version 2) as | |
8584 | + * published by the Free Software Foundation. | |
8585 | + * | |
8586 | + * This program is distributed in the hope that it will be useful, | |
8587 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8588 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
8589 | + * GNU General Public License for more details. | |
8590 | + * | |
8591 | + * You should have received a copy of the GNU General Public License | |
8592 | + * along with this program; if not, write to the Free Software Foundation, | |
8593 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
8594 | + */ | |
8595 | + | |
8596 | +#include <linux/module.h> | |
8597 | +#include <linux/init.h> | |
8598 | +#include <linux/version.h> | |
8599 | +#include <linux/i2c.h> | |
8600 | +#include <linux/videodev.h> | |
8601 | +#include <linux/video_decoder.h> | |
8602 | +#include <linux/ioctl.h> | |
8603 | + | |
8604 | +#include "wis-i2c.h" | |
8605 | + | |
8606 | +struct wis_tw2804 { | |
8607 | + int channel; | |
8608 | + int norm; | |
8609 | + int brightness; | |
8610 | + int contrast; | |
8611 | + int saturation; | |
8612 | + int hue; | |
8613 | +}; | |
8614 | + | |
8615 | +static u8 global_registers[] = | |
8616 | +{ | |
8617 | + 0x39, 0x00, | |
8618 | + 0x3a, 0xff, | |
8619 | + 0x3b, 0x84, | |
8620 | + 0x3c, 0x80, | |
8621 | + 0x3d, 0x80, | |
8622 | + 0x3e, 0x82, | |
8623 | + 0x3f, 0x82, | |
8624 | + 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ | |
8625 | +}; | |
8626 | + | |
8627 | +static u8 channel_registers[] = | |
8628 | +{ | |
8629 | + 0x01, 0xc4, | |
8630 | + 0x02, 0xa5, | |
8631 | + 0x03, 0x20, | |
8632 | + 0x04, 0xd0, | |
8633 | + 0x05, 0x20, | |
8634 | + 0x06, 0xd0, | |
8635 | + 0x07, 0x88, | |
8636 | + 0x08, 0x20, | |
8637 | + 0x09, 0x07, | |
8638 | + 0x0a, 0xf0, | |
8639 | + 0x0b, 0x07, | |
8640 | + 0x0c, 0xf0, | |
8641 | + 0x0d, 0x40, | |
8642 | + 0x0e, 0xd2, | |
8643 | + 0x0f, 0x80, | |
8644 | + 0x10, 0x80, | |
8645 | + 0x11, 0x80, | |
8646 | + 0x12, 0x80, | |
8647 | + 0x13, 0x1f, | |
8648 | + 0x14, 0x00, | |
8649 | + 0x15, 0x00, | |
8650 | + 0x16, 0x00, | |
8651 | + 0x17, 0x00, | |
8652 | + 0x18, 0xff, | |
8653 | + 0x19, 0xff, | |
8654 | + 0x1a, 0xff, | |
8655 | + 0x1b, 0xff, | |
8656 | + 0x1c, 0xff, | |
8657 | + 0x1d, 0xff, | |
8658 | + 0x1e, 0xff, | |
8659 | + 0x1f, 0xff, | |
8660 | + 0x20, 0x07, | |
8661 | + 0x21, 0x07, | |
8662 | + 0x22, 0x00, | |
8663 | + 0x23, 0x91, | |
8664 | + 0x24, 0x51, | |
8665 | + 0x25, 0x03, | |
8666 | + 0x26, 0x00, | |
8667 | + 0x27, 0x00, | |
8668 | + 0x28, 0x00, | |
8669 | + 0x29, 0x00, | |
8670 | + 0x2a, 0x00, | |
8671 | + 0x2b, 0x00, | |
8672 | + 0x2c, 0x00, | |
8673 | + 0x2d, 0x00, | |
8674 | + 0x2e, 0x00, | |
8675 | + 0x2f, 0x00, | |
8676 | + 0x30, 0x00, | |
8677 | + 0x31, 0x00, | |
8678 | + 0x32, 0x00, | |
8679 | + 0x33, 0x00, | |
8680 | + 0x34, 0x00, | |
8681 | + 0x35, 0x00, | |
8682 | + 0x36, 0x00, | |
8683 | + 0x37, 0x00, | |
8684 | + 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ | |
8685 | +}; | |
8686 | + | |
8687 | +static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel) | |
8688 | +{ | |
8689 | + return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); | |
8690 | +} | |
8691 | + | |
8692 | +static int write_regs(struct i2c_client *client, u8 *regs, int channel) | |
8693 | +{ | |
8694 | + int i; | |
8695 | + | |
8696 | + for (i = 0; regs[i] != 0xff; i += 2) | |
8697 | + if (i2c_smbus_write_byte_data(client, | |
8698 | + regs[i] | (channel << 6), regs[i + 1]) < 0) | |
8699 | + return -1; | |
8700 | + return 0; | |
8701 | +} | |
8702 | + | |
8703 | +static int wis_tw2804_command(struct i2c_client *client, | |
8704 | + unsigned int cmd, void *arg) | |
8705 | +{ | |
8706 | + struct wis_tw2804 *dec = i2c_get_clientdata(client); | |
8707 | + | |
8708 | + if (cmd == DECODER_SET_CHANNEL) { | |
8709 | + int *input = arg; | |
8710 | + | |
8711 | + if (*input < 0 || *input > 3) { | |
8712 | + printk(KERN_ERR "wis-tw2804: channel %d is not " | |
8713 | + "between 0 and 3!\n", *input); | |
8714 | + return 0; | |
8715 | + } | |
8716 | + dec->channel = *input; | |
8717 | + printk(KERN_DEBUG "wis-tw2804: initializing TW2804 " | |
8718 | + "channel %d\n", dec->channel); | |
8719 | + if (dec->channel == 0 && | |
8720 | + write_regs(client, global_registers, 0) < 0) { | |
8721 | + printk(KERN_ERR "wis-tw2804: error initializing " | |
8722 | + "TW2804 global registers\n"); | |
8723 | + return 0; | |
8724 | + } | |
8725 | + if (write_regs(client, channel_registers, dec->channel) < 0) { | |
8726 | + printk(KERN_ERR "wis-tw2804: error initializing " | |
8727 | + "TW2804 channel %d\n", dec->channel); | |
8728 | + return 0; | |
8729 | + } | |
8730 | + return 0; | |
8731 | + } | |
8732 | + | |
8733 | + if (dec->channel < 0) { | |
8734 | + printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until " | |
8735 | + "channel number is set\n", cmd); | |
8736 | + return 0; | |
8737 | + } | |
8738 | + | |
8739 | + switch (cmd) { | |
8740 | + case DECODER_SET_NORM: | |
8741 | + { | |
8742 | + int *input = arg; | |
8743 | + u8 regs[] = { | |
8744 | + 0x01, *input == VIDEO_MODE_NTSC ? 0xc4 : 0x84, | |
8745 | + 0x09, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, | |
8746 | + 0x0a, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, | |
8747 | + 0x0b, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, | |
8748 | + 0x0c, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, | |
8749 | + 0x0d, *input == VIDEO_MODE_NTSC ? 0x40 : 0x4a, | |
8750 | + 0x16, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, | |
8751 | + 0x17, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, | |
8752 | + 0x20, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, | |
8753 | + 0x21, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, | |
8754 | + 0xff, 0xff, | |
8755 | + }; | |
8756 | + write_regs(client, regs, dec->channel); | |
8757 | + dec->norm = *input; | |
8758 | + break; | |
8759 | + } | |
8760 | + case VIDIOC_QUERYCTRL: | |
8761 | + { | |
8762 | + struct v4l2_queryctrl *ctrl = arg; | |
8763 | + | |
8764 | + switch (ctrl->id) { | |
8765 | + case V4L2_CID_BRIGHTNESS: | |
8766 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
8767 | + strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); | |
8768 | + ctrl->minimum = 0; | |
8769 | + ctrl->maximum = 255; | |
8770 | + ctrl->step = 1; | |
8771 | + ctrl->default_value = 128; | |
8772 | + ctrl->flags = 0; | |
8773 | + break; | |
8774 | + case V4L2_CID_CONTRAST: | |
8775 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
8776 | + strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); | |
8777 | + ctrl->minimum = 0; | |
8778 | + ctrl->maximum = 255; | |
8779 | + ctrl->step = 1; | |
8780 | + ctrl->default_value = 128; | |
8781 | + ctrl->flags = 0; | |
8782 | + break; | |
8783 | + case V4L2_CID_SATURATION: | |
8784 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
8785 | + strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); | |
8786 | + ctrl->minimum = 0; | |
8787 | + ctrl->maximum = 255; | |
8788 | + ctrl->step = 1; | |
8789 | + ctrl->default_value = 128; | |
8790 | + ctrl->flags = 0; | |
8791 | + break; | |
8792 | + case V4L2_CID_HUE: | |
8793 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
8794 | + strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); | |
8795 | + ctrl->minimum = 0; | |
8796 | + ctrl->maximum = 255; | |
8797 | + ctrl->step = 1; | |
8798 | + ctrl->default_value = 128; | |
8799 | + ctrl->flags = 0; | |
8800 | + break; | |
8801 | + } | |
8802 | + break; | |
8803 | + } | |
8804 | + case VIDIOC_S_CTRL: | |
8805 | + { | |
8806 | + struct v4l2_control *ctrl = arg; | |
8807 | + | |
8808 | + switch (ctrl->id) { | |
8809 | + case V4L2_CID_BRIGHTNESS: | |
8810 | + if (ctrl->value > 255) | |
8811 | + dec->brightness = 255; | |
8812 | + else if (ctrl->value < 0) | |
8813 | + dec->brightness = 0; | |
8814 | + else | |
8815 | + dec->brightness = ctrl->value; | |
8816 | + write_reg(client, 0x12, dec->brightness, dec->channel); | |
8817 | + break; | |
8818 | + case V4L2_CID_CONTRAST: | |
8819 | + if (ctrl->value > 255) | |
8820 | + dec->contrast = 255; | |
8821 | + else if (ctrl->value < 0) | |
8822 | + dec->contrast = 0; | |
8823 | + else | |
8824 | + dec->contrast = ctrl->value; | |
8825 | + write_reg(client, 0x11, dec->contrast, dec->channel); | |
8826 | + break; | |
8827 | + case V4L2_CID_SATURATION: | |
8828 | + if (ctrl->value > 255) | |
8829 | + dec->saturation = 255; | |
8830 | + else if (ctrl->value < 0) | |
8831 | + dec->saturation = 0; | |
8832 | + else | |
8833 | + dec->saturation = ctrl->value; | |
8834 | + write_reg(client, 0x10, dec->saturation, dec->channel); | |
8835 | + break; | |
8836 | + case V4L2_CID_HUE: | |
8837 | + if (ctrl->value > 255) | |
8838 | + dec->hue = 255; | |
8839 | + else if (ctrl->value < 0) | |
8840 | + dec->hue = 0; | |
8841 | + else | |
8842 | + dec->hue = ctrl->value; | |
8843 | + write_reg(client, 0x0f, dec->hue, dec->channel); | |
8844 | + break; | |
8845 | + } | |
8846 | + break; | |
8847 | + } | |
8848 | + case VIDIOC_G_CTRL: | |
8849 | + { | |
8850 | + struct v4l2_control *ctrl = arg; | |
8851 | + | |
8852 | + switch (ctrl->id) { | |
8853 | + case V4L2_CID_BRIGHTNESS: | |
8854 | + ctrl->value = dec->brightness; | |
8855 | + break; | |
8856 | + case V4L2_CID_CONTRAST: | |
8857 | + ctrl->value = dec->contrast; | |
8858 | + break; | |
8859 | + case V4L2_CID_SATURATION: | |
8860 | + ctrl->value = dec->saturation; | |
8861 | + break; | |
8862 | + case V4L2_CID_HUE: | |
8863 | + ctrl->value = dec->hue; | |
8864 | + break; | |
8865 | + } | |
8866 | + break; | |
8867 | + } | |
8868 | + default: | |
8869 | + break; | |
8870 | + } | |
8871 | + return 0; | |
8872 | +} | |
8873 | + | |
8874 | +static struct i2c_driver wis_tw2804_driver; | |
8875 | + | |
8876 | +static struct i2c_client wis_tw2804_client_templ = { | |
8877 | + .name = "TW2804 (WIS)", | |
8878 | + .driver = &wis_tw2804_driver, | |
8879 | +}; | |
8880 | + | |
8881 | +static int wis_tw2804_detect(struct i2c_adapter *adapter, int addr, int kind) | |
8882 | +{ | |
8883 | + struct i2c_client *client; | |
8884 | + struct wis_tw2804 *dec; | |
8885 | + | |
8886 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
8887 | + return 0; | |
8888 | + | |
8889 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
8890 | + if (client == NULL) | |
8891 | + return -ENOMEM; | |
8892 | + memcpy(client, &wis_tw2804_client_templ, | |
8893 | + sizeof(wis_tw2804_client_templ)); | |
8894 | + client->adapter = adapter; | |
8895 | + client->addr = addr; | |
8896 | + | |
8897 | + dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL); | |
8898 | + if (dec == NULL) { | |
8899 | + kfree(client); | |
8900 | + return -ENOMEM; | |
8901 | + } | |
8902 | + dec->channel = -1; | |
8903 | + dec->norm = VIDEO_MODE_NTSC; | |
8904 | + dec->brightness = 128; | |
8905 | + dec->contrast = 128; | |
8906 | + dec->saturation = 128; | |
8907 | + dec->hue = 128; | |
8908 | + i2c_set_clientdata(client, dec); | |
8909 | + | |
8910 | + printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n", | |
8911 | + addr, adapter->name); | |
8912 | + | |
8913 | + i2c_attach_client(client); | |
8914 | + return 0; | |
8915 | +} | |
8916 | + | |
8917 | +static int wis_tw2804_detach(struct i2c_client *client) | |
8918 | +{ | |
8919 | + struct wis_tw2804 *dec = i2c_get_clientdata(client); | |
8920 | + int r; | |
8921 | + | |
8922 | + r = i2c_detach_client(client); | |
8923 | + if (r < 0) | |
8924 | + return r; | |
8925 | + | |
8926 | + kfree(client); | |
8927 | + kfree(dec); | |
8928 | + return 0; | |
8929 | +} | |
8930 | + | |
8931 | +static struct i2c_driver wis_tw2804_driver = { | |
8932 | + .driver = { | |
8933 | + .name = "WIS TW2804 I2C driver", | |
8934 | + }, | |
8935 | + .id = I2C_DRIVERID_WIS_TW2804, | |
8936 | + .detach_client = wis_tw2804_detach, | |
8937 | + .command = wis_tw2804_command, | |
8938 | +}; | |
8939 | + | |
8940 | +static int __init wis_tw2804_init(void) | |
8941 | +{ | |
8942 | + int r; | |
8943 | + | |
8944 | + r = i2c_add_driver(&wis_tw2804_driver); | |
8945 | + if (r < 0) | |
8946 | + return r; | |
8947 | + return wis_i2c_add_driver(wis_tw2804_driver.id, wis_tw2804_detect); | |
8948 | +} | |
8949 | + | |
8950 | +static void __exit wis_tw2804_cleanup(void) | |
8951 | +{ | |
8952 | + wis_i2c_del_driver(wis_tw2804_detect); | |
8953 | + i2c_del_driver(&wis_tw2804_driver); | |
8954 | +} | |
8955 | + | |
8956 | +module_init(wis_tw2804_init); | |
8957 | +module_exit(wis_tw2804_cleanup); | |
8958 | + | |
8959 | +MODULE_LICENSE("GPL v2"); | |
8960 | diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c | |
8961 | new file mode 100644 | |
8962 | index 0000000..1cdf01a | |
8963 | --- /dev/null | |
8964 | +++ b/drivers/staging/go7007/wis-tw9903.c | |
8965 | @@ -0,0 +1,363 @@ | |
8966 | +/* | |
8967 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
8968 | + * | |
8969 | + * This program is free software; you can redistribute it and/or modify | |
8970 | + * it under the terms of the GNU General Public License (Version 2) as | |
8971 | + * published by the Free Software Foundation. | |
8972 | + * | |
8973 | + * This program is distributed in the hope that it will be useful, | |
8974 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8975 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
8976 | + * GNU General Public License for more details. | |
8977 | + * | |
8978 | + * You should have received a copy of the GNU General Public License | |
8979 | + * along with this program; if not, write to the Free Software Foundation, | |
8980 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
8981 | + */ | |
8982 | + | |
8983 | +#include <linux/module.h> | |
8984 | +#include <linux/init.h> | |
8985 | +#include <linux/version.h> | |
8986 | +#include <linux/i2c.h> | |
8987 | +#include <linux/videodev.h> | |
8988 | +#include <linux/video_decoder.h> | |
8989 | +#include <linux/ioctl.h> | |
8990 | + | |
8991 | +#include "wis-i2c.h" | |
8992 | + | |
8993 | +struct wis_tw9903 { | |
8994 | + int norm; | |
8995 | + int brightness; | |
8996 | + int contrast; | |
8997 | + int hue; | |
8998 | +}; | |
8999 | + | |
9000 | +static u8 initial_registers[] = | |
9001 | +{ | |
9002 | + 0x02, 0x44, /* input 1, composite */ | |
9003 | + 0x03, 0x92, /* correct digital format */ | |
9004 | + 0x04, 0x00, | |
9005 | + 0x05, 0x80, /* or 0x00 for PAL */ | |
9006 | + 0x06, 0x40, /* second internal current reference */ | |
9007 | + 0x07, 0x02, /* window */ | |
9008 | + 0x08, 0x14, /* window */ | |
9009 | + 0x09, 0xf0, /* window */ | |
9010 | + 0x0a, 0x81, /* window */ | |
9011 | + 0x0b, 0xd0, /* window */ | |
9012 | + 0x0c, 0x8c, | |
9013 | + 0x0d, 0x00, /* scaling */ | |
9014 | + 0x0e, 0x11, /* scaling */ | |
9015 | + 0x0f, 0x00, /* scaling */ | |
9016 | + 0x10, 0x00, /* brightness */ | |
9017 | + 0x11, 0x60, /* contrast */ | |
9018 | + 0x12, 0x01, /* sharpness */ | |
9019 | + 0x13, 0x7f, /* U gain */ | |
9020 | + 0x14, 0x5a, /* V gain */ | |
9021 | + 0x15, 0x00, /* hue */ | |
9022 | + 0x16, 0xc3, /* sharpness */ | |
9023 | + 0x18, 0x00, | |
9024 | + 0x19, 0x58, /* vbi */ | |
9025 | + 0x1a, 0x80, | |
9026 | + 0x1c, 0x0f, /* video norm */ | |
9027 | + 0x1d, 0x7f, /* video norm */ | |
9028 | + 0x20, 0xa0, /* clamping gain (working 0x50) */ | |
9029 | + 0x21, 0x22, | |
9030 | + 0x22, 0xf0, | |
9031 | + 0x23, 0xfe, | |
9032 | + 0x24, 0x3c, | |
9033 | + 0x25, 0x38, | |
9034 | + 0x26, 0x44, | |
9035 | + 0x27, 0x20, | |
9036 | + 0x28, 0x00, | |
9037 | + 0x29, 0x15, | |
9038 | + 0x2a, 0xa0, | |
9039 | + 0x2b, 0x44, | |
9040 | + 0x2c, 0x37, | |
9041 | + 0x2d, 0x00, | |
9042 | + 0x2e, 0xa5, /* burst PLL control (working: a9) */ | |
9043 | + 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */ | |
9044 | + 0x31, 0x00, | |
9045 | + 0x33, 0x22, | |
9046 | + 0x34, 0x11, | |
9047 | + 0x35, 0x35, | |
9048 | + 0x3b, 0x05, | |
9049 | + 0x06, 0xc0, /* reset device */ | |
9050 | + 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ | |
9051 | +}; | |
9052 | + | |
9053 | +static int write_reg(struct i2c_client *client, u8 reg, u8 value) | |
9054 | +{ | |
9055 | + return i2c_smbus_write_byte_data(client, reg, value); | |
9056 | +} | |
9057 | + | |
9058 | +static int write_regs(struct i2c_client *client, u8 *regs) | |
9059 | +{ | |
9060 | + int i; | |
9061 | + | |
9062 | + for (i = 0; regs[i] != 0x00; i += 2) | |
9063 | + if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) | |
9064 | + return -1; | |
9065 | + return 0; | |
9066 | +} | |
9067 | + | |
9068 | +static int wis_tw9903_command(struct i2c_client *client, | |
9069 | + unsigned int cmd, void *arg) | |
9070 | +{ | |
9071 | + struct wis_tw9903 *dec = i2c_get_clientdata(client); | |
9072 | + | |
9073 | + switch (cmd) { | |
9074 | + case DECODER_SET_INPUT: | |
9075 | + { | |
9076 | + int *input = arg; | |
9077 | + | |
9078 | + i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1)); | |
9079 | + break; | |
9080 | + } | |
9081 | +#if 0 /* The scaler on this thing seems to be horribly broken */ | |
9082 | + case DECODER_SET_RESOLUTION: | |
9083 | + { | |
9084 | + struct video_decoder_resolution *res = arg; | |
9085 | + /*int hscale = 256 * 720 / res->width;*/ | |
9086 | + int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); | |
9087 | + int vscale = 256 * (dec->norm == VIDEO_MODE_NTSC ? 240 : 288) | |
9088 | + / res->height; | |
9089 | + u8 regs[] = { | |
9090 | + 0x0d, vscale & 0xff, | |
9091 | + 0x0f, hscale & 0xff, | |
9092 | + 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8), | |
9093 | + 0x06, 0xc0, /* reset device */ | |
9094 | + 0, 0, | |
9095 | + }; | |
9096 | + printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n", | |
9097 | + vscale, hscale); | |
9098 | + /*write_regs(client, regs);*/ | |
9099 | + break; | |
9100 | + } | |
9101 | +#endif | |
9102 | + case DECODER_SET_NORM: | |
9103 | + { | |
9104 | + int *input = arg; | |
9105 | + u8 regs[] = { | |
9106 | + 0x05, *input == VIDEO_MODE_NTSC ? 0x80 : 0x00, | |
9107 | + 0x07, *input == VIDEO_MODE_NTSC ? 0x02 : 0x12, | |
9108 | + 0x08, *input == VIDEO_MODE_NTSC ? 0x14 : 0x18, | |
9109 | + 0x09, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, | |
9110 | + 0, 0, | |
9111 | + }; | |
9112 | + write_regs(client, regs); | |
9113 | + dec->norm = *input; | |
9114 | + break; | |
9115 | + } | |
9116 | + case VIDIOC_QUERYCTRL: | |
9117 | + { | |
9118 | + struct v4l2_queryctrl *ctrl = arg; | |
9119 | + | |
9120 | + switch (ctrl->id) { | |
9121 | + case V4L2_CID_BRIGHTNESS: | |
9122 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
9123 | + strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); | |
9124 | + ctrl->minimum = -128; | |
9125 | + ctrl->maximum = 127; | |
9126 | + ctrl->step = 1; | |
9127 | + ctrl->default_value = 0x00; | |
9128 | + ctrl->flags = 0; | |
9129 | + break; | |
9130 | + case V4L2_CID_CONTRAST: | |
9131 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
9132 | + strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); | |
9133 | + ctrl->minimum = 0; | |
9134 | + ctrl->maximum = 255; | |
9135 | + ctrl->step = 1; | |
9136 | + ctrl->default_value = 0x60; | |
9137 | + ctrl->flags = 0; | |
9138 | + break; | |
9139 | +#if 0 | |
9140 | + /* I don't understand how the Chroma Gain registers work... */ | |
9141 | + case V4L2_CID_SATURATION: | |
9142 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
9143 | + strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); | |
9144 | + ctrl->minimum = 0; | |
9145 | + ctrl->maximum = 127; | |
9146 | + ctrl->step = 1; | |
9147 | + ctrl->default_value = 64; | |
9148 | + ctrl->flags = 0; | |
9149 | + break; | |
9150 | +#endif | |
9151 | + case V4L2_CID_HUE: | |
9152 | + ctrl->type = V4L2_CTRL_TYPE_INTEGER; | |
9153 | + strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); | |
9154 | + ctrl->minimum = -128; | |
9155 | + ctrl->maximum = 127; | |
9156 | + ctrl->step = 1; | |
9157 | + ctrl->default_value = 0; | |
9158 | + ctrl->flags = 0; | |
9159 | + break; | |
9160 | + } | |
9161 | + break; | |
9162 | + } | |
9163 | + case VIDIOC_S_CTRL: | |
9164 | + { | |
9165 | + struct v4l2_control *ctrl = arg; | |
9166 | + | |
9167 | + switch (ctrl->id) { | |
9168 | + case V4L2_CID_BRIGHTNESS: | |
9169 | + if (ctrl->value > 127) | |
9170 | + dec->brightness = 127; | |
9171 | + else if (ctrl->value < -128) | |
9172 | + dec->brightness = -128; | |
9173 | + else | |
9174 | + dec->brightness = ctrl->value; | |
9175 | + write_reg(client, 0x10, dec->brightness); | |
9176 | + break; | |
9177 | + case V4L2_CID_CONTRAST: | |
9178 | + if (ctrl->value > 255) | |
9179 | + dec->contrast = 255; | |
9180 | + else if (ctrl->value < 0) | |
9181 | + dec->contrast = 0; | |
9182 | + else | |
9183 | + dec->contrast = ctrl->value; | |
9184 | + write_reg(client, 0x11, dec->contrast); | |
9185 | + break; | |
9186 | +#if 0 | |
9187 | + case V4L2_CID_SATURATION: | |
9188 | + if (ctrl->value > 127) | |
9189 | + dec->saturation = 127; | |
9190 | + else if (ctrl->value < 0) | |
9191 | + dec->saturation = 0; | |
9192 | + else | |
9193 | + dec->saturation = ctrl->value; | |
9194 | + /*write_reg(client, 0x0c, dec->saturation);*/ | |
9195 | + break; | |
9196 | +#endif | |
9197 | + case V4L2_CID_HUE: | |
9198 | + if (ctrl->value > 127) | |
9199 | + dec->hue = 127; | |
9200 | + else if (ctrl->value < -128) | |
9201 | + dec->hue = -128; | |
9202 | + else | |
9203 | + dec->hue = ctrl->value; | |
9204 | + write_reg(client, 0x15, dec->hue); | |
9205 | + break; | |
9206 | + } | |
9207 | + break; | |
9208 | + } | |
9209 | + case VIDIOC_G_CTRL: | |
9210 | + { | |
9211 | + struct v4l2_control *ctrl = arg; | |
9212 | + | |
9213 | + switch (ctrl->id) { | |
9214 | + case V4L2_CID_BRIGHTNESS: | |
9215 | + ctrl->value = dec->brightness; | |
9216 | + break; | |
9217 | + case V4L2_CID_CONTRAST: | |
9218 | + ctrl->value = dec->contrast; | |
9219 | + break; | |
9220 | +#if 0 | |
9221 | + case V4L2_CID_SATURATION: | |
9222 | + ctrl->value = dec->saturation; | |
9223 | + break; | |
9224 | +#endif | |
9225 | + case V4L2_CID_HUE: | |
9226 | + ctrl->value = dec->hue; | |
9227 | + break; | |
9228 | + } | |
9229 | + break; | |
9230 | + } | |
9231 | + default: | |
9232 | + break; | |
9233 | + } | |
9234 | + return 0; | |
9235 | +} | |
9236 | + | |
9237 | +static struct i2c_driver wis_tw9903_driver; | |
9238 | + | |
9239 | +static struct i2c_client wis_tw9903_client_templ = { | |
9240 | + .name = "TW9903 (WIS)", | |
9241 | + .driver = &wis_tw9903_driver, | |
9242 | +}; | |
9243 | + | |
9244 | +static int wis_tw9903_detect(struct i2c_adapter *adapter, int addr, int kind) | |
9245 | +{ | |
9246 | + struct i2c_client *client; | |
9247 | + struct wis_tw9903 *dec; | |
9248 | + | |
9249 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
9250 | + return 0; | |
9251 | + | |
9252 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
9253 | + if (client == NULL) | |
9254 | + return -ENOMEM; | |
9255 | + memcpy(client, &wis_tw9903_client_templ, | |
9256 | + sizeof(wis_tw9903_client_templ)); | |
9257 | + client->adapter = adapter; | |
9258 | + client->addr = addr; | |
9259 | + | |
9260 | + dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); | |
9261 | + if (dec == NULL) { | |
9262 | + kfree(client); | |
9263 | + return -ENOMEM; | |
9264 | + } | |
9265 | + dec->norm = VIDEO_MODE_NTSC; | |
9266 | + dec->brightness = 0; | |
9267 | + dec->contrast = 0x60; | |
9268 | + dec->hue = 0; | |
9269 | + i2c_set_clientdata(client, dec); | |
9270 | + | |
9271 | + printk(KERN_DEBUG | |
9272 | + "wis-tw9903: initializing TW9903 at address %d on %s\n", | |
9273 | + addr, adapter->name); | |
9274 | + | |
9275 | + if (write_regs(client, initial_registers) < 0) { | |
9276 | + printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); | |
9277 | + kfree(client); | |
9278 | + kfree(dec); | |
9279 | + return 0; | |
9280 | + } | |
9281 | + | |
9282 | + i2c_attach_client(client); | |
9283 | + return 0; | |
9284 | +} | |
9285 | + | |
9286 | +static int wis_tw9903_detach(struct i2c_client *client) | |
9287 | +{ | |
9288 | + struct wis_tw9903 *dec = i2c_get_clientdata(client); | |
9289 | + int r; | |
9290 | + | |
9291 | + r = i2c_detach_client(client); | |
9292 | + if (r < 0) | |
9293 | + return r; | |
9294 | + | |
9295 | + kfree(client); | |
9296 | + kfree(dec); | |
9297 | + return 0; | |
9298 | +} | |
9299 | + | |
9300 | +static struct i2c_driver wis_tw9903_driver = { | |
9301 | + .driver = { | |
9302 | + .name = "WIS TW9903 I2C driver", | |
9303 | + }, | |
9304 | + .id = I2C_DRIVERID_WIS_TW9903, | |
9305 | + .detach_client = wis_tw9903_detach, | |
9306 | + .command = wis_tw9903_command, | |
9307 | +}; | |
9308 | + | |
9309 | +static int __init wis_tw9903_init(void) | |
9310 | +{ | |
9311 | + int r; | |
9312 | + | |
9313 | + r = i2c_add_driver(&wis_tw9903_driver); | |
9314 | + if (r < 0) | |
9315 | + return r; | |
9316 | + return wis_i2c_add_driver(wis_tw9903_driver.id, wis_tw9903_detect); | |
9317 | +} | |
9318 | + | |
9319 | +static void __exit wis_tw9903_cleanup(void) | |
9320 | +{ | |
9321 | + wis_i2c_del_driver(wis_tw9903_detect); | |
9322 | + i2c_del_driver(&wis_tw9903_driver); | |
9323 | +} | |
9324 | + | |
9325 | +module_init(wis_tw9903_init); | |
9326 | +module_exit(wis_tw9903_cleanup); | |
9327 | + | |
9328 | +MODULE_LICENSE("GPL v2"); | |
9329 | diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c | |
9330 | new file mode 100644 | |
9331 | index 0000000..28c10bf | |
9332 | --- /dev/null | |
9333 | +++ b/drivers/staging/go7007/wis-uda1342.c | |
9334 | @@ -0,0 +1,136 @@ | |
9335 | +/* | |
9336 | + * Copyright (C) 2005-2006 Micronas USA Inc. | |
9337 | + * | |
9338 | + * This program is free software; you can redistribute it and/or modify | |
9339 | + * it under the terms of the GNU General Public License (Version 2) as | |
9340 | + * published by the Free Software Foundation. | |
9341 | + * | |
9342 | + * This program is distributed in the hope that it will be useful, | |
9343 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9344 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
9345 | + * GNU General Public License for more details. | |
9346 | + * | |
9347 | + * You should have received a copy of the GNU General Public License | |
9348 | + * along with this program; if not, write to the Free Software Foundation, | |
9349 | + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
9350 | + */ | |
9351 | + | |
9352 | +#include <linux/module.h> | |
9353 | +#include <linux/init.h> | |
9354 | +#include <linux/version.h> | |
9355 | +#include <linux/i2c.h> | |
9356 | +#include <linux/videodev.h> | |
9357 | +#include <media/tvaudio.h> | |
9358 | +#include <media/v4l2-common.h> | |
9359 | + | |
9360 | +#include "wis-i2c.h" | |
9361 | + | |
9362 | +static int write_reg(struct i2c_client *client, int reg, int value) | |
9363 | +{ | |
9364 | + /* UDA1342 wants MSB first, but SMBus sends LSB first */ | |
9365 | + i2c_smbus_write_word_data(client, reg, swab16(value)); | |
9366 | + return 0; | |
9367 | +} | |
9368 | + | |
9369 | +static int wis_uda1342_command(struct i2c_client *client, | |
9370 | + unsigned int cmd, void *arg) | |
9371 | +{ | |
9372 | + switch (cmd) { | |
9373 | + case VIDIOC_S_AUDIO: | |
9374 | + { | |
9375 | + int *inp = arg; | |
9376 | + | |
9377 | + switch (*inp) { | |
9378 | + case TVAUDIO_INPUT_TUNER: | |
9379 | + write_reg(client, 0x00, 0x1441); /* select input 2 */ | |
9380 | + break; | |
9381 | + case TVAUDIO_INPUT_EXTERN: | |
9382 | + write_reg(client, 0x00, 0x1241); /* select input 1 */ | |
9383 | + break; | |
9384 | + default: | |
9385 | + printk(KERN_ERR "wis-uda1342: input %d not supported\n", | |
9386 | + *inp); | |
9387 | + break; | |
9388 | + } | |
9389 | + break; | |
9390 | + } | |
9391 | + default: | |
9392 | + break; | |
9393 | + } | |
9394 | + return 0; | |
9395 | +} | |
9396 | + | |
9397 | +static struct i2c_driver wis_uda1342_driver; | |
9398 | + | |
9399 | +static struct i2c_client wis_uda1342_client_templ = { | |
9400 | + .name = "UDA1342 (WIS)", | |
9401 | + .driver = &wis_uda1342_driver, | |
9402 | +}; | |
9403 | + | |
9404 | +static int wis_uda1342_detect(struct i2c_adapter *adapter, int addr, int kind) | |
9405 | +{ | |
9406 | + struct i2c_client *client; | |
9407 | + | |
9408 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
9409 | + return 0; | |
9410 | + | |
9411 | + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | |
9412 | + if (client == NULL) | |
9413 | + return -ENOMEM; | |
9414 | + memcpy(client, &wis_uda1342_client_templ, | |
9415 | + sizeof(wis_uda1342_client_templ)); | |
9416 | + client->adapter = adapter; | |
9417 | + client->addr = addr; | |
9418 | + | |
9419 | + printk(KERN_DEBUG | |
9420 | + "wis-uda1342: initializing UDA1342 at address %d on %s\n", | |
9421 | + addr, adapter->name); | |
9422 | + | |
9423 | + write_reg(client, 0x00, 0x8000); /* reset registers */ | |
9424 | + write_reg(client, 0x00, 0x1241); /* select input 1 */ | |
9425 | + | |
9426 | + i2c_attach_client(client); | |
9427 | + return 0; | |
9428 | +} | |
9429 | + | |
9430 | +static int wis_uda1342_detach(struct i2c_client *client) | |
9431 | +{ | |
9432 | + int r; | |
9433 | + | |
9434 | + r = i2c_detach_client(client); | |
9435 | + if (r < 0) | |
9436 | + return r; | |
9437 | + | |
9438 | + kfree(client); | |
9439 | + return 0; | |
9440 | +} | |
9441 | + | |
9442 | +static struct i2c_driver wis_uda1342_driver = { | |
9443 | + .driver = { | |
9444 | + .name = "WIS UDA1342 I2C driver", | |
9445 | + }, | |
9446 | + .id = I2C_DRIVERID_WIS_UDA1342, | |
9447 | + .detach_client = wis_uda1342_detach, | |
9448 | + .command = wis_uda1342_command, | |
9449 | +}; | |
9450 | + | |
9451 | +static int __init wis_uda1342_init(void) | |
9452 | +{ | |
9453 | + int r; | |
9454 | + | |
9455 | + r = i2c_add_driver(&wis_uda1342_driver); | |
9456 | + if (r < 0) | |
9457 | + return r; | |
9458 | + return wis_i2c_add_driver(wis_uda1342_driver.id, wis_uda1342_detect); | |
9459 | +} | |
9460 | + | |
9461 | +static void __exit wis_uda1342_cleanup(void) | |
9462 | +{ | |
9463 | + wis_i2c_del_driver(wis_uda1342_detect); | |
9464 | + i2c_del_driver(&wis_uda1342_driver); | |
9465 | +} | |
9466 | + | |
9467 | +module_init(wis_uda1342_init); | |
9468 | +module_exit(wis_uda1342_cleanup); | |
9469 | + | |
9470 | +MODULE_LICENSE("GPL v2"); | |
9471 | -- | |
9472 | 1.6.0.2 | |
9473 |