xref: /linux/drivers/media/usb/go7007/go7007-driver.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2866b8695SGreg Kroah-Hartman /*
3866b8695SGreg Kroah-Hartman  * Copyright (C) 2005-2006 Micronas USA Inc.
4866b8695SGreg Kroah-Hartman  */
5866b8695SGreg Kroah-Hartman 
6866b8695SGreg Kroah-Hartman #include <linux/module.h>
7866b8695SGreg Kroah-Hartman #include <linux/delay.h>
8866b8695SGreg Kroah-Hartman #include <linux/sched.h>
9866b8695SGreg Kroah-Hartman #include <linux/spinlock.h>
10866b8695SGreg Kroah-Hartman #include <linux/unistd.h>
11866b8695SGreg Kroah-Hartman #include <linux/time.h>
12866b8695SGreg Kroah-Hartman #include <linux/mm.h>
13866b8695SGreg Kroah-Hartman #include <linux/vmalloc.h>
14866b8695SGreg Kroah-Hartman #include <linux/device.h>
15866b8695SGreg Kroah-Hartman #include <linux/i2c.h>
16866b8695SGreg Kroah-Hartman #include <linux/firmware.h>
17fd9a40daSMauro Carvalho Chehab #include <linux/mutex.h>
18866b8695SGreg Kroah-Hartman #include <linux/uaccess.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
20df20d69eSRoss Cohen #include <linux/videodev2.h>
21866b8695SGreg Kroah-Hartman #include <media/tuner.h>
22866b8695SGreg Kroah-Hartman #include <media/v4l2-common.h>
230ee58f84SHans Verkuil #include <media/v4l2-event.h>
24866b8695SGreg Kroah-Hartman 
25866b8695SGreg Kroah-Hartman #include "go7007-priv.h"
26866b8695SGreg Kroah-Hartman 
27866b8695SGreg Kroah-Hartman /*
28866b8695SGreg Kroah-Hartman  * Wait for an interrupt to be delivered from the GO7007SB and return
29866b8695SGreg Kroah-Hartman  * the associated value and data.
30866b8695SGreg Kroah-Hartman  *
31866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
32866b8695SGreg Kroah-Hartman  */
33866b8695SGreg Kroah-Hartman int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data)
34866b8695SGreg Kroah-Hartman {
35866b8695SGreg Kroah-Hartman 	go->interrupt_available = 0;
36866b8695SGreg Kroah-Hartman 	go->hpi_ops->read_interrupt(go);
37866b8695SGreg Kroah-Hartman 	if (wait_event_timeout(go->interrupt_waitq,
38866b8695SGreg Kroah-Hartman 				go->interrupt_available, 5*HZ) < 0) {
390b398f4fSPete Eberlein 		v4l2_err(&go->v4l2_dev, "timeout waiting for read interrupt\n");
40866b8695SGreg Kroah-Hartman 		return -1;
41866b8695SGreg Kroah-Hartman 	}
42866b8695SGreg Kroah-Hartman 	if (!go->interrupt_available)
43866b8695SGreg Kroah-Hartman 		return -1;
44866b8695SGreg Kroah-Hartman 	go->interrupt_available = 0;
45866b8695SGreg Kroah-Hartman 	*value = go->interrupt_value & 0xfffe;
46866b8695SGreg Kroah-Hartman 	*data = go->interrupt_data;
47866b8695SGreg Kroah-Hartman 	return 0;
48866b8695SGreg Kroah-Hartman }
49866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_read_interrupt);
50866b8695SGreg Kroah-Hartman 
51866b8695SGreg Kroah-Hartman /*
52866b8695SGreg Kroah-Hartman  * Read a register/address on the GO7007SB.
53866b8695SGreg Kroah-Hartman  *
54866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
55866b8695SGreg Kroah-Hartman  */
56866b8695SGreg Kroah-Hartman int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data)
57866b8695SGreg Kroah-Hartman {
58866b8695SGreg Kroah-Hartman 	int count = 100;
59866b8695SGreg Kroah-Hartman 	u16 value;
60866b8695SGreg Kroah-Hartman 
61866b8695SGreg Kroah-Hartman 	if (go7007_write_interrupt(go, 0x0010, addr) < 0)
62866b8695SGreg Kroah-Hartman 		return -EIO;
63866b8695SGreg Kroah-Hartman 	while (count-- > 0) {
64866b8695SGreg Kroah-Hartman 		if (go7007_read_interrupt(go, &value, data) == 0 &&
65866b8695SGreg Kroah-Hartman 				value == 0xa000)
66866b8695SGreg Kroah-Hartman 			return 0;
67866b8695SGreg Kroah-Hartman 	}
68866b8695SGreg Kroah-Hartman 	return -EIO;
69866b8695SGreg Kroah-Hartman }
70866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_read_addr);
71866b8695SGreg Kroah-Hartman 
72866b8695SGreg Kroah-Hartman /*
73866b8695SGreg Kroah-Hartman  * Send the boot firmware to the encoder, which just wakes it up and lets
74866b8695SGreg Kroah-Hartman  * us talk to the GPIO pins and on-board I2C adapter.
75866b8695SGreg Kroah-Hartman  *
76866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
77866b8695SGreg Kroah-Hartman  */
78866b8695SGreg Kroah-Hartman static int go7007_load_encoder(struct go7007 *go)
79866b8695SGreg Kroah-Hartman {
80866b8695SGreg Kroah-Hartman 	const struct firmware *fw_entry;
810ee3d4d5SHans Verkuil 	char fw_name[] = "go7007/go7007fw.bin";
82866b8695SGreg Kroah-Hartman 	void *bounce;
83866b8695SGreg Kroah-Hartman 	int fw_len, rv = 0;
84866b8695SGreg Kroah-Hartman 	u16 intr_val, intr_data;
85866b8695SGreg Kroah-Hartman 
8695ef3940SHans Verkuil 	if (go->boot_fw == NULL) {
87866b8695SGreg Kroah-Hartman 		if (request_firmware(&fw_entry, fw_name, go->dev)) {
8895ef3940SHans Verkuil 			v4l2_err(go, "unable to load firmware from file \"%s\"\n", fw_name);
89866b8695SGreg Kroah-Hartman 			return -1;
90866b8695SGreg Kroah-Hartman 		}
91866b8695SGreg Kroah-Hartman 		if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
9295ef3940SHans Verkuil 			v4l2_err(go, "file \"%s\" does not appear to be go7007 firmware\n", fw_name);
93866b8695SGreg Kroah-Hartman 			release_firmware(fw_entry);
94866b8695SGreg Kroah-Hartman 			return -1;
95866b8695SGreg Kroah-Hartman 		}
96866b8695SGreg Kroah-Hartman 		fw_len = fw_entry->size - 16;
9742f9de6eSPeter Huewe 		bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL);
98866b8695SGreg Kroah-Hartman 		if (bounce == NULL) {
9995ef3940SHans Verkuil 			v4l2_err(go, "unable to allocate %d bytes for firmware transfer\n", fw_len);
100866b8695SGreg Kroah-Hartman 			release_firmware(fw_entry);
101866b8695SGreg Kroah-Hartman 			return -1;
102866b8695SGreg Kroah-Hartman 		}
103866b8695SGreg Kroah-Hartman 		release_firmware(fw_entry);
10495ef3940SHans Verkuil 		go->boot_fw_len = fw_len;
10595ef3940SHans Verkuil 		go->boot_fw = bounce;
10695ef3940SHans Verkuil 	}
107866b8695SGreg Kroah-Hartman 	if (go7007_interface_reset(go) < 0 ||
10895ef3940SHans Verkuil 	    go7007_send_firmware(go, go->boot_fw, go->boot_fw_len) < 0 ||
109866b8695SGreg Kroah-Hartman 	    go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
110866b8695SGreg Kroah-Hartman 			(intr_val & ~0x1) != 0x5a5a) {
11162474076SPete Eberlein 		v4l2_err(go, "error transferring firmware\n");
112866b8695SGreg Kroah-Hartman 		rv = -1;
113866b8695SGreg Kroah-Hartman 	}
114866b8695SGreg Kroah-Hartman 	return rv;
115866b8695SGreg Kroah-Hartman }
116866b8695SGreg Kroah-Hartman 
1170ee3d4d5SHans Verkuil MODULE_FIRMWARE("go7007/go7007fw.bin");
1185d929a71SBen Hutchings 
119866b8695SGreg Kroah-Hartman /*
120866b8695SGreg Kroah-Hartman  * Boot the encoder and register the I2C adapter if requested.  Do the
121866b8695SGreg Kroah-Hartman  * minimum initialization necessary, since the board-specific code may
122866b8695SGreg Kroah-Hartman  * still need to probe the board ID.
123866b8695SGreg Kroah-Hartman  *
124866b8695SGreg Kroah-Hartman  * Must NOT be called with the hw_lock held.
125866b8695SGreg Kroah-Hartman  */
126866b8695SGreg Kroah-Hartman int go7007_boot_encoder(struct go7007 *go, int init_i2c)
127866b8695SGreg Kroah-Hartman {
128866b8695SGreg Kroah-Hartman 	int ret;
129866b8695SGreg Kroah-Hartman 
130fd9a40daSMauro Carvalho Chehab 	mutex_lock(&go->hw_lock);
131866b8695SGreg Kroah-Hartman 	ret = go7007_load_encoder(go);
132fd9a40daSMauro Carvalho Chehab 	mutex_unlock(&go->hw_lock);
133866b8695SGreg Kroah-Hartman 	if (ret < 0)
134866b8695SGreg Kroah-Hartman 		return -1;
135866b8695SGreg Kroah-Hartman 	if (!init_i2c)
136866b8695SGreg Kroah-Hartman 		return 0;
137866b8695SGreg Kroah-Hartman 	if (go7007_i2c_init(go) < 0)
138866b8695SGreg Kroah-Hartman 		return -1;
139866b8695SGreg Kroah-Hartman 	go->i2c_adapter_online = 1;
140866b8695SGreg Kroah-Hartman 	return 0;
141866b8695SGreg Kroah-Hartman }
142866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_boot_encoder);
143866b8695SGreg Kroah-Hartman 
144866b8695SGreg Kroah-Hartman /*
145866b8695SGreg Kroah-Hartman  * Configure any hardware-related registers in the GO7007, such as GPIO
146866b8695SGreg Kroah-Hartman  * pins and bus parameters, which are board-specific.  This assumes
147866b8695SGreg Kroah-Hartman  * the boot firmware has already been downloaded.
148866b8695SGreg Kroah-Hartman  *
149866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
150866b8695SGreg Kroah-Hartman  */
151866b8695SGreg Kroah-Hartman static int go7007_init_encoder(struct go7007 *go)
152866b8695SGreg Kroah-Hartman {
153866b8695SGreg Kroah-Hartman 	if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) {
154866b8695SGreg Kroah-Hartman 		go7007_write_addr(go, 0x1000, 0x0811);
155866b8695SGreg Kroah-Hartman 		go7007_write_addr(go, 0x1000, 0x0c11);
156866b8695SGreg Kroah-Hartman 	}
1571f1aed2eSHans Verkuil 	switch (go->board_id) {
1581f1aed2eSHans Verkuil 	case GO7007_BOARDID_MATRIX_REV:
159866b8695SGreg Kroah-Hartman 		/* Set GPIO pin 0 to be an output (audio clock control) */
160866b8695SGreg Kroah-Hartman 		go7007_write_addr(go, 0x3c82, 0x0001);
161866b8695SGreg Kroah-Hartman 		go7007_write_addr(go, 0x3c80, 0x00fe);
1621f1aed2eSHans Verkuil 		break;
1631f1aed2eSHans Verkuil 	case GO7007_BOARDID_ADLINK_MPG24:
164d18b6acfSVolokh Konstantin 		/* set GPIO5 to be an output, currently low */
165d18b6acfSVolokh Konstantin 		go7007_write_addr(go, 0x3c82, 0x0000);
166d18b6acfSVolokh Konstantin 		go7007_write_addr(go, 0x3c80, 0x00df);
1671f1aed2eSHans Verkuil 		break;
1681f1aed2eSHans Verkuil 	case GO7007_BOARDID_ADS_USBAV_709:
1691f1aed2eSHans Verkuil 		/* GPIO pin 0: audio clock control */
1701f1aed2eSHans Verkuil 		/*      pin 2: TW9906 reset */
1711f1aed2eSHans Verkuil 		/*      pin 3: capture LED */
1721f1aed2eSHans Verkuil 		go7007_write_addr(go, 0x3c82, 0x000d);
1731f1aed2eSHans Verkuil 		go7007_write_addr(go, 0x3c80, 0x00f2);
1741f1aed2eSHans Verkuil 		break;
175d18b6acfSVolokh Konstantin 	}
176866b8695SGreg Kroah-Hartman 	return 0;
177866b8695SGreg Kroah-Hartman }
178866b8695SGreg Kroah-Hartman 
179866b8695SGreg Kroah-Hartman /*
180866b8695SGreg Kroah-Hartman  * Send the boot firmware to the GO7007 and configure the registers.  This
181866b8695SGreg Kroah-Hartman  * is the only way to stop the encoder once it has started streaming video.
182866b8695SGreg Kroah-Hartman  *
183866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
184866b8695SGreg Kroah-Hartman  */
185866b8695SGreg Kroah-Hartman int go7007_reset_encoder(struct go7007 *go)
186866b8695SGreg Kroah-Hartman {
187866b8695SGreg Kroah-Hartman 	if (go7007_load_encoder(go) < 0)
188866b8695SGreg Kroah-Hartman 		return -1;
189866b8695SGreg Kroah-Hartman 	return go7007_init_encoder(go);
190866b8695SGreg Kroah-Hartman }
191866b8695SGreg Kroah-Hartman 
192866b8695SGreg Kroah-Hartman /*
193866b8695SGreg Kroah-Hartman  * Attempt to instantiate an I2C client by ID, probably loading a module.
194866b8695SGreg Kroah-Hartman  */
195dcafb6deSVolokh Konstantin static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *const i2c)
196866b8695SGreg Kroah-Hartman {
197fa3c39bdSPete Eberlein 	struct go7007 *go = i2c_get_adapdata(adapter);
198fa3c39bdSPete Eberlein 	struct v4l2_device *v4l2_dev = &go->v4l2_dev;
1993acd16abSHans Verkuil 	struct v4l2_subdev *sd;
200dcafb6deSVolokh Konstantin 	struct i2c_board_info info;
201866b8695SGreg Kroah-Hartman 
202dcafb6deSVolokh Konstantin 	memset(&info, 0, sizeof(info));
203c0decac1SMauro Carvalho Chehab 	strscpy(info.type, i2c->type, sizeof(info.type));
204dcafb6deSVolokh Konstantin 	info.addr = i2c->addr;
205dcafb6deSVolokh Konstantin 	info.flags = i2c->flags;
206dcafb6deSVolokh Konstantin 
2073acd16abSHans Verkuil 	sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL);
2083acd16abSHans Verkuil 	if (sd) {
2093acd16abSHans Verkuil 		if (i2c->is_video)
2103acd16abSHans Verkuil 			go->sd_video = sd;
2113acd16abSHans Verkuil 		if (i2c->is_audio)
2123acd16abSHans Verkuil 			go->sd_audio = sd;
213866b8695SGreg Kroah-Hartman 		return 0;
2143acd16abSHans Verkuil 	}
215fa3c39bdSPete Eberlein 
2169707cb55SHans Verkuil 	pr_info("go7007: probing for module i2c:%s failed\n", i2c->type);
217dcafb6deSVolokh Konstantin 	return -EINVAL;
218866b8695SGreg Kroah-Hartman }
219866b8695SGreg Kroah-Hartman 
220866b8695SGreg Kroah-Hartman /*
221d5d3a7ccSHans Verkuil  * Detach and unregister the encoder.  The go7007 struct won't be freed
222d5d3a7ccSHans Verkuil  * until v4l2 finishes releasing its resources and all associated fds are
223d5d3a7ccSHans Verkuil  * closed by applications.
224d5d3a7ccSHans Verkuil  */
225d5d3a7ccSHans Verkuil static void go7007_remove(struct v4l2_device *v4l2_dev)
226d5d3a7ccSHans Verkuil {
227d5d3a7ccSHans Verkuil 	struct go7007 *go = container_of(v4l2_dev, struct go7007, v4l2_dev);
228d5d3a7ccSHans Verkuil 
229d5d3a7ccSHans Verkuil 	v4l2_device_unregister(v4l2_dev);
230d5d3a7ccSHans Verkuil 	if (go->hpi_ops->release)
231d5d3a7ccSHans Verkuil 		go->hpi_ops->release(go);
232d5d3a7ccSHans Verkuil 	if (go->i2c_adapter_online) {
23399bece77SLinus Torvalds 		i2c_del_adapter(&go->i2c_adapter);
234d5d3a7ccSHans Verkuil 		go->i2c_adapter_online = 0;
235d5d3a7ccSHans Verkuil 	}
236d5d3a7ccSHans Verkuil 
237d5d3a7ccSHans Verkuil 	kfree(go->boot_fw);
238d5d3a7ccSHans Verkuil 	go7007_v4l2_remove(go);
239d5d3a7ccSHans Verkuil 	kfree(go);
240d5d3a7ccSHans Verkuil }
241d5d3a7ccSHans Verkuil 
242d5d3a7ccSHans Verkuil /*
243866b8695SGreg Kroah-Hartman  * Finalize the GO7007 hardware setup, register the on-board I2C adapter
244866b8695SGreg Kroah-Hartman  * (if used on this board), load the I2C client driver for the sensor
245866b8695SGreg Kroah-Hartman  * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2
246866b8695SGreg Kroah-Hartman  * interfaces.
247866b8695SGreg Kroah-Hartman  *
248866b8695SGreg Kroah-Hartman  * Must NOT be called with the hw_lock held.
249866b8695SGreg Kroah-Hartman  */
2503acd16abSHans Verkuil int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs)
251866b8695SGreg Kroah-Hartman {
252866b8695SGreg Kroah-Hartman 	int i, ret;
253866b8695SGreg Kroah-Hartman 
2546d569502SYAMANE Toshiaki 	dev_info(go->dev, "go7007: registering new %s\n", go->name);
255866b8695SGreg Kroah-Hartman 
256d5d3a7ccSHans Verkuil 	go->v4l2_dev.release = go7007_remove;
257d5d3a7ccSHans Verkuil 	ret = v4l2_device_register(go->dev, &go->v4l2_dev);
258d5d3a7ccSHans Verkuil 	if (ret < 0)
259d5d3a7ccSHans Verkuil 		return ret;
260d5d3a7ccSHans Verkuil 
261fd9a40daSMauro Carvalho Chehab 	mutex_lock(&go->hw_lock);
262866b8695SGreg Kroah-Hartman 	ret = go7007_init_encoder(go);
263fd9a40daSMauro Carvalho Chehab 	mutex_unlock(&go->hw_lock);
264866b8695SGreg Kroah-Hartman 	if (ret < 0)
2659b8451d5SHans Verkuil 		return ret;
2669b8451d5SHans Verkuil 
2679b8451d5SHans Verkuil 	ret = go7007_v4l2_ctrl_init(go);
2689b8451d5SHans Verkuil 	if (ret < 0)
2699b8451d5SHans Verkuil 		return ret;
270866b8695SGreg Kroah-Hartman 
271866b8695SGreg Kroah-Hartman 	if (!go->i2c_adapter_online &&
272866b8695SGreg Kroah-Hartman 			go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
2739b8451d5SHans Verkuil 		ret = go7007_i2c_init(go);
2749b8451d5SHans Verkuil 		if (ret < 0)
2759b8451d5SHans Verkuil 			return ret;
276866b8695SGreg Kroah-Hartman 		go->i2c_adapter_online = 1;
277866b8695SGreg Kroah-Hartman 	}
278866b8695SGreg Kroah-Hartman 	if (go->i2c_adapter_online) {
2791f1aed2eSHans Verkuil 		if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) {
2801f1aed2eSHans Verkuil 			/* Reset the TW9906 */
2811f1aed2eSHans Verkuil 			go7007_write_addr(go, 0x3c82, 0x0009);
2821f1aed2eSHans Verkuil 			msleep(50);
2831f1aed2eSHans Verkuil 			go7007_write_addr(go, 0x3c82, 0x000d);
2841f1aed2eSHans Verkuil 		}
2853acd16abSHans Verkuil 		for (i = 0; i < num_i2c_devs; ++i)
286dcafb6deSVolokh Konstantin 			init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]);
2873acd16abSHans Verkuil 
2883acd16abSHans Verkuil 		if (go->tuner_type >= 0) {
2893acd16abSHans Verkuil 			struct tuner_setup setup = {
2903acd16abSHans Verkuil 				.addr = ADDR_UNSET,
2913acd16abSHans Verkuil 				.type = go->tuner_type,
2923acd16abSHans Verkuil 				.mode_mask = T_ANALOG_TV,
2933acd16abSHans Verkuil 			};
2943acd16abSHans Verkuil 
2953acd16abSHans Verkuil 			v4l2_device_call_all(&go->v4l2_dev, 0, tuner,
2963acd16abSHans Verkuil 				s_type_addr, &setup);
2973acd16abSHans Verkuil 		}
298866b8695SGreg Kroah-Hartman 		if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
2993acd16abSHans Verkuil 			v4l2_subdev_call(go->sd_video, video, s_routing,
3003acd16abSHans Verkuil 					0, 0, go->channel_number + 1);
301866b8695SGreg Kroah-Hartman 	}
302d5d3a7ccSHans Verkuil 
303d5d3a7ccSHans Verkuil 	ret = go7007_v4l2_init(go);
304d5d3a7ccSHans Verkuil 	if (ret < 0)
305d5d3a7ccSHans Verkuil 		return ret;
306d5d3a7ccSHans Verkuil 
307866b8695SGreg Kroah-Hartman 	if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
308866b8695SGreg Kroah-Hartman 		go->audio_enabled = 1;
309866b8695SGreg Kroah-Hartman 		go7007_snd_init(go);
310866b8695SGreg Kroah-Hartman 	}
311fa3c39bdSPete Eberlein 	return 0;
312866b8695SGreg Kroah-Hartman }
313866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_register_encoder);
314866b8695SGreg Kroah-Hartman 
315866b8695SGreg Kroah-Hartman /*
316866b8695SGreg Kroah-Hartman  * Send the encode firmware to the encoder, which will cause it
317866b8695SGreg Kroah-Hartman  * to immediately start delivering the video and audio streams.
318866b8695SGreg Kroah-Hartman  *
319866b8695SGreg Kroah-Hartman  * Must be called with the hw_lock held.
320866b8695SGreg Kroah-Hartman  */
321866b8695SGreg Kroah-Hartman int go7007_start_encoder(struct go7007 *go)
322866b8695SGreg Kroah-Hartman {
323866b8695SGreg Kroah-Hartman 	u8 *fw;
3240ee58f84SHans Verkuil 	int fw_len, rv = 0, i, x, y;
325866b8695SGreg Kroah-Hartman 	u16 intr_val, intr_data;
326866b8695SGreg Kroah-Hartman 
327866b8695SGreg Kroah-Hartman 	go->modet_enable = 0;
3280ee58f84SHans Verkuil 	for (i = 0; i < 4; i++)
3290ee58f84SHans Verkuil 		go->modet[i].enable = 0;
3300ee58f84SHans Verkuil 
3310ee58f84SHans Verkuil 	switch (v4l2_ctrl_g_ctrl(go->modet_mode)) {
3320ee58f84SHans Verkuil 	case V4L2_DETECT_MD_MODE_GLOBAL:
3330ee58f84SHans Verkuil 		memset(go->modet_map, 0, sizeof(go->modet_map));
3340ee58f84SHans Verkuil 		go->modet[0].enable = 1;
335866b8695SGreg Kroah-Hartman 		go->modet_enable = 1;
3360ee58f84SHans Verkuil 		break;
3370ee58f84SHans Verkuil 	case V4L2_DETECT_MD_MODE_REGION_GRID:
3380ee58f84SHans Verkuil 		for (y = 0; y < go->height / 16; y++) {
3390ee58f84SHans Verkuil 			for (x = 0; x < go->width / 16; x++) {
3400ee58f84SHans Verkuil 				int idx = y * go->width / 16 + x;
3410ee58f84SHans Verkuil 
3420ee58f84SHans Verkuil 				go->modet[go->modet_map[idx]].enable = 1;
343866b8695SGreg Kroah-Hartman 			}
344866b8695SGreg Kroah-Hartman 		}
3450ee58f84SHans Verkuil 		go->modet_enable = 1;
3460ee58f84SHans Verkuil 		break;
3470ee58f84SHans Verkuil 	}
3480ee58f84SHans Verkuil 
3490ee58f84SHans Verkuil 	if (go->dvd_mode)
3500ee58f84SHans Verkuil 		go->modet_enable = 0;
351866b8695SGreg Kroah-Hartman 
352866b8695SGreg Kroah-Hartman 	if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
353866b8695SGreg Kroah-Hartman 		return -1;
354866b8695SGreg Kroah-Hartman 
355866b8695SGreg Kroah-Hartman 	if (go7007_send_firmware(go, fw, fw_len) < 0 ||
356866b8695SGreg Kroah-Hartman 			go7007_read_interrupt(go, &intr_val, &intr_data) < 0) {
3570b398f4fSPete Eberlein 		v4l2_err(&go->v4l2_dev, "error transferring firmware\n");
358866b8695SGreg Kroah-Hartman 		rv = -1;
359866b8695SGreg Kroah-Hartman 		goto start_error;
360866b8695SGreg Kroah-Hartman 	}
361866b8695SGreg Kroah-Hartman 
362866b8695SGreg Kroah-Hartman 	go->state = STATE_DATA;
363866b8695SGreg Kroah-Hartman 	go->parse_length = 0;
364866b8695SGreg Kroah-Hartman 	go->seen_frame = 0;
365866b8695SGreg Kroah-Hartman 	if (go7007_stream_start(go) < 0) {
3660b398f4fSPete Eberlein 		v4l2_err(&go->v4l2_dev, "error starting stream transfer\n");
367866b8695SGreg Kroah-Hartman 		rv = -1;
368866b8695SGreg Kroah-Hartman 		goto start_error;
369866b8695SGreg Kroah-Hartman 	}
370866b8695SGreg Kroah-Hartman 
371866b8695SGreg Kroah-Hartman start_error:
372866b8695SGreg Kroah-Hartman 	kfree(fw);
373866b8695SGreg Kroah-Hartman 	return rv;
374866b8695SGreg Kroah-Hartman }
375866b8695SGreg Kroah-Hartman 
376866b8695SGreg Kroah-Hartman /*
377866b8695SGreg Kroah-Hartman  * Store a byte in the current video buffer, if there is one.
378866b8695SGreg Kroah-Hartman  */
379ffcc1c08SHans Verkuil static inline void store_byte(struct go7007_buffer *vb, u8 byte)
380866b8695SGreg Kroah-Hartman {
3812d700715SJunghak Sung 	if (vb && vb->vb.vb2_buf.planes[0].bytesused < GO7007_BUF_SIZE) {
3822d700715SJunghak Sung 		u8 *ptr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0);
383866b8695SGreg Kroah-Hartman 
3842d700715SJunghak Sung 		ptr[vb->vb.vb2_buf.planes[0].bytesused++] = byte;
385866b8695SGreg Kroah-Hartman 	}
386866b8695SGreg Kroah-Hartman }
387866b8695SGreg Kroah-Hartman 
3880ee58f84SHans Verkuil static void go7007_set_motion_regions(struct go7007 *go, struct go7007_buffer *vb,
3890ee58f84SHans Verkuil 		u32 motion_regions)
3900ee58f84SHans Verkuil {
3910ee58f84SHans Verkuil 	if (motion_regions != go->modet_event_status) {
3920ee58f84SHans Verkuil 		struct v4l2_event ev = {
3930ee58f84SHans Verkuil 			.type = V4L2_EVENT_MOTION_DET,
3940ee58f84SHans Verkuil 			.u.motion_det = {
3950ee58f84SHans Verkuil 				.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
3962d700715SJunghak Sung 				.frame_sequence = vb->vb.sequence,
3970ee58f84SHans Verkuil 				.region_mask = motion_regions,
3980ee58f84SHans Verkuil 			},
3990ee58f84SHans Verkuil 		};
4000ee58f84SHans Verkuil 
4010ee58f84SHans Verkuil 		v4l2_event_queue(&go->vdev, &ev);
4020ee58f84SHans Verkuil 		go->modet_event_status = motion_regions;
4030ee58f84SHans Verkuil 	}
4040ee58f84SHans Verkuil }
4050ee58f84SHans Verkuil 
4060ee58f84SHans Verkuil /*
4070ee58f84SHans Verkuil  * Determine regions with motion and send a motion detection event
4080ee58f84SHans Verkuil  * in case of changes.
4090ee58f84SHans Verkuil  */
4100ee58f84SHans Verkuil static void go7007_motion_regions(struct go7007 *go, struct go7007_buffer *vb)
4110ee58f84SHans Verkuil {
4122d700715SJunghak Sung 	u32 *bytesused = &vb->vb.vb2_buf.planes[0].bytesused;
4130ee58f84SHans Verkuil 	unsigned motion[4] = { 0, 0, 0, 0 };
4140ee58f84SHans Verkuil 	u32 motion_regions = 0;
4150ee58f84SHans Verkuil 	unsigned stride = (go->width + 7) >> 3;
4160ee58f84SHans Verkuil 	unsigned x, y;
4170ee58f84SHans Verkuil 	int i;
4180ee58f84SHans Verkuil 
4190ee58f84SHans Verkuil 	for (i = 0; i < 216; ++i)
4200ee58f84SHans Verkuil 		store_byte(vb, go->active_map[i]);
4210ee58f84SHans Verkuil 	for (y = 0; y < go->height / 16; y++) {
4220ee58f84SHans Verkuil 		for (x = 0; x < go->width / 16; x++) {
4230ee58f84SHans Verkuil 			if (!(go->active_map[y * stride + (x >> 3)] & (1 << (x & 7))))
4240ee58f84SHans Verkuil 				continue;
4250ee58f84SHans Verkuil 			motion[go->modet_map[y * (go->width / 16) + x]]++;
4260ee58f84SHans Verkuil 		}
4270ee58f84SHans Verkuil 	}
4280ee58f84SHans Verkuil 	motion_regions = ((motion[0] > 0) << 0) |
4290ee58f84SHans Verkuil 			 ((motion[1] > 0) << 1) |
4300ee58f84SHans Verkuil 			 ((motion[2] > 0) << 2) |
4310ee58f84SHans Verkuil 			 ((motion[3] > 0) << 3);
4320ee58f84SHans Verkuil 	*bytesused -= 216;
4330ee58f84SHans Verkuil 	go7007_set_motion_regions(go, vb, motion_regions);
4340ee58f84SHans Verkuil }
4350ee58f84SHans Verkuil 
436866b8695SGreg Kroah-Hartman /*
437866b8695SGreg Kroah-Hartman  * Deliver the last video buffer and get a new one to start writing to.
438866b8695SGreg Kroah-Hartman  */
439ffcc1c08SHans Verkuil static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
440866b8695SGreg Kroah-Hartman {
441747598d5SMauro Carvalho Chehab 	u32 *bytesused;
4420ee58f84SHans Verkuil 	struct go7007_buffer *vb_tmp = NULL;
443a4733b52SSebastian Andrzej Siewior 	unsigned long flags;
444866b8695SGreg Kroah-Hartman 
4450ee58f84SHans Verkuil 	if (vb == NULL) {
446a4733b52SSebastian Andrzej Siewior 		spin_lock_irqsave(&go->spinlock, flags);
4470ee58f84SHans Verkuil 		if (!list_empty(&go->vidq_active))
4480ee58f84SHans Verkuil 			vb = go->active_buf =
4490ee58f84SHans Verkuil 				list_first_entry(&go->vidq_active, struct go7007_buffer, list);
450a4733b52SSebastian Andrzej Siewior 		spin_unlock_irqrestore(&go->spinlock, flags);
4510ee58f84SHans Verkuil 		go->next_seq++;
4520ee58f84SHans Verkuil 		return vb;
453866b8695SGreg Kroah-Hartman 	}
4542d700715SJunghak Sung 	bytesused = &vb->vb.vb2_buf.planes[0].bytesused;
4550ee58f84SHans Verkuil 
4562d700715SJunghak Sung 	vb->vb.sequence = go->next_seq++;
4570ee58f84SHans Verkuil 	if (vb->modet_active && *bytesused + 216 < GO7007_BUF_SIZE)
4580ee58f84SHans Verkuil 		go7007_motion_regions(go, vb);
4590ee58f84SHans Verkuil 	else
4600ee58f84SHans Verkuil 		go7007_set_motion_regions(go, vb, 0);
4610ee58f84SHans Verkuil 
462d6dd645eSJunghak Sung 	vb->vb.vb2_buf.timestamp = ktime_get_ns();
463ffcc1c08SHans Verkuil 	vb_tmp = vb;
464a4733b52SSebastian Andrzej Siewior 	spin_lock_irqsave(&go->spinlock, flags);
465ffcc1c08SHans Verkuil 	list_del(&vb->list);
466ffcc1c08SHans Verkuil 	if (list_empty(&go->vidq_active))
467ffcc1c08SHans Verkuil 		vb = NULL;
468ffcc1c08SHans Verkuil 	else
4692d700715SJunghak Sung 		vb = list_first_entry(&go->vidq_active,
4702d700715SJunghak Sung 				struct go7007_buffer, list);
471ffcc1c08SHans Verkuil 	go->active_buf = vb;
472a4733b52SSebastian Andrzej Siewior 	spin_unlock_irqrestore(&go->spinlock, flags);
4732d700715SJunghak Sung 	vb2_buffer_done(&vb_tmp->vb.vb2_buf, VB2_BUF_STATE_DONE);
474ffcc1c08SHans Verkuil 	return vb;
475866b8695SGreg Kroah-Hartman }
476866b8695SGreg Kroah-Hartman 
477866b8695SGreg Kroah-Hartman static void write_bitmap_word(struct go7007 *go)
478866b8695SGreg Kroah-Hartman {
479866b8695SGreg Kroah-Hartman 	int x, y, i, stride = ((go->width >> 4) + 7) >> 3;
480866b8695SGreg Kroah-Hartman 
481866b8695SGreg Kroah-Hartman 	for (i = 0; i < 16; ++i) {
482866b8695SGreg Kroah-Hartman 		y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
483866b8695SGreg Kroah-Hartman 		x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
484a716e9d7SPete Eberlein 		if (stride * y + (x >> 3) < sizeof(go->active_map))
485866b8695SGreg Kroah-Hartman 			go->active_map[stride * y + (x >> 3)] |=
486866b8695SGreg Kroah-Hartman 					(go->modet_word & 1) << (x & 0x7);
487866b8695SGreg Kroah-Hartman 		go->modet_word >>= 1;
488866b8695SGreg Kroah-Hartman 	}
489866b8695SGreg Kroah-Hartman }
490866b8695SGreg Kroah-Hartman 
491866b8695SGreg Kroah-Hartman /*
492866b8695SGreg Kroah-Hartman  * Parse a chunk of the video stream into frames.  The frames are not
493866b8695SGreg Kroah-Hartman  * delimited by the hardware, so we have to parse the frame boundaries
494866b8695SGreg Kroah-Hartman  * based on the type of video stream we're receiving.
495866b8695SGreg Kroah-Hartman  */
496866b8695SGreg Kroah-Hartman void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
497866b8695SGreg Kroah-Hartman {
498ffcc1c08SHans Verkuil 	struct go7007_buffer *vb = go->active_buf;
499ac41fa2aSHans Verkuil 	int i, seq_start_code = -1, gop_start_code = -1, frame_start_code = -1;
500866b8695SGreg Kroah-Hartman 
501866b8695SGreg Kroah-Hartman 	switch (go->format) {
50235d2d76dSHans Verkuil 	case V4L2_PIX_FMT_MPEG4:
503866b8695SGreg Kroah-Hartman 		seq_start_code = 0xB0;
504ac41fa2aSHans Verkuil 		gop_start_code = 0xB3;
505866b8695SGreg Kroah-Hartman 		frame_start_code = 0xB6;
506866b8695SGreg Kroah-Hartman 		break;
50735d2d76dSHans Verkuil 	case V4L2_PIX_FMT_MPEG1:
50835d2d76dSHans Verkuil 	case V4L2_PIX_FMT_MPEG2:
509866b8695SGreg Kroah-Hartman 		seq_start_code = 0xB3;
510ac41fa2aSHans Verkuil 		gop_start_code = 0xB8;
511866b8695SGreg Kroah-Hartman 		frame_start_code = 0x00;
512866b8695SGreg Kroah-Hartman 		break;
513866b8695SGreg Kroah-Hartman 	}
514866b8695SGreg Kroah-Hartman 
515866b8695SGreg Kroah-Hartman 	for (i = 0; i < length; ++i) {
5162d700715SJunghak Sung 		if (vb && vb->vb.vb2_buf.planes[0].bytesused >=
5172d700715SJunghak Sung 				GO7007_BUF_SIZE - 3) {
5180b398f4fSPete Eberlein 			v4l2_info(&go->v4l2_dev, "dropping oversized frame\n");
5192d700715SJunghak Sung 			vb->vb.vb2_buf.planes[0].bytesused = 0;
520ffcc1c08SHans Verkuil 			vb->frame_offset = 0;
521ffcc1c08SHans Verkuil 			vb->modet_active = 0;
522ffcc1c08SHans Verkuil 			vb = go->active_buf = NULL;
523866b8695SGreg Kroah-Hartman 		}
524866b8695SGreg Kroah-Hartman 
525866b8695SGreg Kroah-Hartman 		switch (go->state) {
526866b8695SGreg Kroah-Hartman 		case STATE_DATA:
527866b8695SGreg Kroah-Hartman 			switch (buf[i]) {
528866b8695SGreg Kroah-Hartman 			case 0x00:
529866b8695SGreg Kroah-Hartman 				go->state = STATE_00;
530866b8695SGreg Kroah-Hartman 				break;
531866b8695SGreg Kroah-Hartman 			case 0xFF:
532866b8695SGreg Kroah-Hartman 				go->state = STATE_FF;
533866b8695SGreg Kroah-Hartman 				break;
534866b8695SGreg Kroah-Hartman 			default:
535ffcc1c08SHans Verkuil 				store_byte(vb, buf[i]);
536866b8695SGreg Kroah-Hartman 				break;
537866b8695SGreg Kroah-Hartman 			}
538866b8695SGreg Kroah-Hartman 			break;
539866b8695SGreg Kroah-Hartman 		case STATE_00:
540866b8695SGreg Kroah-Hartman 			switch (buf[i]) {
541866b8695SGreg Kroah-Hartman 			case 0x00:
542866b8695SGreg Kroah-Hartman 				go->state = STATE_00_00;
543866b8695SGreg Kroah-Hartman 				break;
544866b8695SGreg Kroah-Hartman 			case 0xFF:
545ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
546866b8695SGreg Kroah-Hartman 				go->state = STATE_FF;
547866b8695SGreg Kroah-Hartman 				break;
548866b8695SGreg Kroah-Hartman 			default:
549ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
550ffcc1c08SHans Verkuil 				store_byte(vb, buf[i]);
551866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
552866b8695SGreg Kroah-Hartman 				break;
553866b8695SGreg Kroah-Hartman 			}
554866b8695SGreg Kroah-Hartman 			break;
555866b8695SGreg Kroah-Hartman 		case STATE_00_00:
556866b8695SGreg Kroah-Hartman 			switch (buf[i]) {
557866b8695SGreg Kroah-Hartman 			case 0x00:
558ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
559866b8695SGreg Kroah-Hartman 				/* go->state remains STATE_00_00 */
560866b8695SGreg Kroah-Hartman 				break;
561866b8695SGreg Kroah-Hartman 			case 0x01:
562866b8695SGreg Kroah-Hartman 				go->state = STATE_00_00_01;
563866b8695SGreg Kroah-Hartman 				break;
564866b8695SGreg Kroah-Hartman 			case 0xFF:
565ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
566ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
567866b8695SGreg Kroah-Hartman 				go->state = STATE_FF;
568866b8695SGreg Kroah-Hartman 				break;
569866b8695SGreg Kroah-Hartman 			default:
570ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
571ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
572ffcc1c08SHans Verkuil 				store_byte(vb, buf[i]);
573866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
574866b8695SGreg Kroah-Hartman 				break;
575866b8695SGreg Kroah-Hartman 			}
576866b8695SGreg Kroah-Hartman 			break;
577866b8695SGreg Kroah-Hartman 		case STATE_00_00_01:
578a716e9d7SPete Eberlein 			if (buf[i] == 0xF8 && go->modet_enable == 0) {
579a716e9d7SPete Eberlein 				/* MODET start code, but MODET not enabled */
580ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
581ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
582ffcc1c08SHans Verkuil 				store_byte(vb, 0x01);
583ffcc1c08SHans Verkuil 				store_byte(vb, 0xF8);
584a716e9d7SPete Eberlein 				go->state = STATE_DATA;
585a716e9d7SPete Eberlein 				break;
586a716e9d7SPete Eberlein 			}
587866b8695SGreg Kroah-Hartman 			/* If this is the start of a new MPEG frame,
588866b8695SGreg Kroah-Hartman 			 * get a new buffer */
58935d2d76dSHans Verkuil 			if ((go->format == V4L2_PIX_FMT_MPEG1 ||
59035d2d76dSHans Verkuil 			     go->format == V4L2_PIX_FMT_MPEG2 ||
59135d2d76dSHans Verkuil 			     go->format == V4L2_PIX_FMT_MPEG4) &&
592866b8695SGreg Kroah-Hartman 			    (buf[i] == seq_start_code ||
593ac41fa2aSHans Verkuil 			     buf[i] == gop_start_code ||
594866b8695SGreg Kroah-Hartman 			     buf[i] == frame_start_code)) {
595ffcc1c08SHans Verkuil 				if (vb == NULL || go->seen_frame)
596ffcc1c08SHans Verkuil 					vb = frame_boundary(go, vb);
597ffcc1c08SHans Verkuil 				go->seen_frame = buf[i] == frame_start_code;
598ffcc1c08SHans Verkuil 				if (vb && go->seen_frame)
5992d700715SJunghak Sung 					vb->frame_offset =
6002d700715SJunghak Sung 					vb->vb.vb2_buf.planes[0].bytesused;
601866b8695SGreg Kroah-Hartman 			}
602866b8695SGreg Kroah-Hartman 			/* Handle any special chunk types, or just write the
603866b8695SGreg Kroah-Hartman 			 * start code to the (potentially new) buffer */
604866b8695SGreg Kroah-Hartman 			switch (buf[i]) {
605866b8695SGreg Kroah-Hartman 			case 0xF5: /* timestamp */
606866b8695SGreg Kroah-Hartman 				go->parse_length = 12;
607866b8695SGreg Kroah-Hartman 				go->state = STATE_UNPARSED;
608866b8695SGreg Kroah-Hartman 				break;
609866b8695SGreg Kroah-Hartman 			case 0xF6: /* vbi */
610866b8695SGreg Kroah-Hartman 				go->state = STATE_VBI_LEN_A;
611866b8695SGreg Kroah-Hartman 				break;
612866b8695SGreg Kroah-Hartman 			case 0xF8: /* MD map */
613866b8695SGreg Kroah-Hartman 				go->parse_length = 0;
614866b8695SGreg Kroah-Hartman 				memset(go->active_map, 0,
615866b8695SGreg Kroah-Hartman 						sizeof(go->active_map));
616866b8695SGreg Kroah-Hartman 				go->state = STATE_MODET_MAP;
617866b8695SGreg Kroah-Hartman 				break;
618866b8695SGreg Kroah-Hartman 			case 0xFF: /* Potential JPEG start code */
619ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
620ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
621ffcc1c08SHans Verkuil 				store_byte(vb, 0x01);
622866b8695SGreg Kroah-Hartman 				go->state = STATE_FF;
623866b8695SGreg Kroah-Hartman 				break;
624866b8695SGreg Kroah-Hartman 			default:
625ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
626ffcc1c08SHans Verkuil 				store_byte(vb, 0x00);
627ffcc1c08SHans Verkuil 				store_byte(vb, 0x01);
628ffcc1c08SHans Verkuil 				store_byte(vb, buf[i]);
629866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
630866b8695SGreg Kroah-Hartman 				break;
631866b8695SGreg Kroah-Hartman 			}
632866b8695SGreg Kroah-Hartman 			break;
633866b8695SGreg Kroah-Hartman 		case STATE_FF:
634866b8695SGreg Kroah-Hartman 			switch (buf[i]) {
635866b8695SGreg Kroah-Hartman 			case 0x00:
636ffcc1c08SHans Verkuil 				store_byte(vb, 0xFF);
637866b8695SGreg Kroah-Hartman 				go->state = STATE_00;
638866b8695SGreg Kroah-Hartman 				break;
639866b8695SGreg Kroah-Hartman 			case 0xFF:
640ffcc1c08SHans Verkuil 				store_byte(vb, 0xFF);
641866b8695SGreg Kroah-Hartman 				/* go->state remains STATE_FF */
642866b8695SGreg Kroah-Hartman 				break;
643866b8695SGreg Kroah-Hartman 			case 0xD8:
64435d2d76dSHans Verkuil 				if (go->format == V4L2_PIX_FMT_MJPEG)
645ffcc1c08SHans Verkuil 					vb = frame_boundary(go, vb);
646*1771e9fbSGustavo A. R. Silva 				fallthrough;
647866b8695SGreg Kroah-Hartman 			default:
648ffcc1c08SHans Verkuil 				store_byte(vb, 0xFF);
649ffcc1c08SHans Verkuil 				store_byte(vb, buf[i]);
650866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
651866b8695SGreg Kroah-Hartman 				break;
652866b8695SGreg Kroah-Hartman 			}
653866b8695SGreg Kroah-Hartman 			break;
654866b8695SGreg Kroah-Hartman 		case STATE_VBI_LEN_A:
655866b8695SGreg Kroah-Hartman 			go->parse_length = buf[i] << 8;
656866b8695SGreg Kroah-Hartman 			go->state = STATE_VBI_LEN_B;
657866b8695SGreg Kroah-Hartman 			break;
658866b8695SGreg Kroah-Hartman 		case STATE_VBI_LEN_B:
659866b8695SGreg Kroah-Hartman 			go->parse_length |= buf[i];
660866b8695SGreg Kroah-Hartman 			if (go->parse_length > 0)
661866b8695SGreg Kroah-Hartman 				go->state = STATE_UNPARSED;
662866b8695SGreg Kroah-Hartman 			else
663866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
664866b8695SGreg Kroah-Hartman 			break;
665866b8695SGreg Kroah-Hartman 		case STATE_MODET_MAP:
666866b8695SGreg Kroah-Hartman 			if (go->parse_length < 204) {
667866b8695SGreg Kroah-Hartman 				if (go->parse_length & 1) {
668866b8695SGreg Kroah-Hartman 					go->modet_word |= buf[i];
669866b8695SGreg Kroah-Hartman 					write_bitmap_word(go);
670866b8695SGreg Kroah-Hartman 				} else
671866b8695SGreg Kroah-Hartman 					go->modet_word = buf[i] << 8;
672ffcc1c08SHans Verkuil 			} else if (go->parse_length == 207 && vb) {
673ffcc1c08SHans Verkuil 				vb->modet_active = buf[i];
674866b8695SGreg Kroah-Hartman 			}
675866b8695SGreg Kroah-Hartman 			if (++go->parse_length == 208)
676866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
677866b8695SGreg Kroah-Hartman 			break;
678866b8695SGreg Kroah-Hartman 		case STATE_UNPARSED:
679866b8695SGreg Kroah-Hartman 			if (--go->parse_length == 0)
680866b8695SGreg Kroah-Hartman 				go->state = STATE_DATA;
681866b8695SGreg Kroah-Hartman 			break;
682866b8695SGreg Kroah-Hartman 		}
683866b8695SGreg Kroah-Hartman 	}
684866b8695SGreg Kroah-Hartman }
685866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_parse_video_stream);
686866b8695SGreg Kroah-Hartman 
687866b8695SGreg Kroah-Hartman /*
688866b8695SGreg Kroah-Hartman  * Allocate a new go7007 struct.  Used by the hardware-specific probe.
689866b8695SGreg Kroah-Hartman  */
6900a6ecbb4SHans Verkuil struct go7007 *go7007_alloc(const struct go7007_board_info *board,
6910a6ecbb4SHans Verkuil 						struct device *dev)
692866b8695SGreg Kroah-Hartman {
693866b8695SGreg Kroah-Hartman 	struct go7007 *go;
694866b8695SGreg Kroah-Hartman 	int i;
695866b8695SGreg Kroah-Hartman 
69661a2353cSVolokh Konstantin 	go = kzalloc(sizeof(struct go7007), GFP_KERNEL);
697866b8695SGreg Kroah-Hartman 	if (go == NULL)
698866b8695SGreg Kroah-Hartman 		return NULL;
699866b8695SGreg Kroah-Hartman 	go->dev = dev;
700866b8695SGreg Kroah-Hartman 	go->board_info = board;
701866b8695SGreg Kroah-Hartman 	go->board_id = 0;
702866b8695SGreg Kroah-Hartman 	go->tuner_type = -1;
703866b8695SGreg Kroah-Hartman 	go->channel_number = 0;
704866b8695SGreg Kroah-Hartman 	go->name[0] = 0;
705fd9a40daSMauro Carvalho Chehab 	mutex_init(&go->hw_lock);
706866b8695SGreg Kroah-Hartman 	init_waitqueue_head(&go->frame_waitq);
707866b8695SGreg Kroah-Hartman 	spin_lock_init(&go->spinlock);
708866b8695SGreg Kroah-Hartman 	go->status = STATUS_INIT;
709866b8695SGreg Kroah-Hartman 	memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
710866b8695SGreg Kroah-Hartman 	go->i2c_adapter_online = 0;
711866b8695SGreg Kroah-Hartman 	go->interrupt_available = 0;
712866b8695SGreg Kroah-Hartman 	init_waitqueue_head(&go->interrupt_waitq);
713866b8695SGreg Kroah-Hartman 	go->input = 0;
71450deb749SHans Verkuil 	go7007_update_board(go);
715866b8695SGreg Kroah-Hartman 	go->encoder_h_halve = 0;
716866b8695SGreg Kroah-Hartman 	go->encoder_v_halve = 0;
717866b8695SGreg Kroah-Hartman 	go->encoder_subsample = 0;
71835d2d76dSHans Verkuil 	go->format = V4L2_PIX_FMT_MJPEG;
719866b8695SGreg Kroah-Hartman 	go->bitrate = 1500000;
720866b8695SGreg Kroah-Hartman 	go->fps_scale = 1;
721866b8695SGreg Kroah-Hartman 	go->pali = 0;
722866b8695SGreg Kroah-Hartman 	go->aspect_ratio = GO7007_RATIO_1_1;
723866b8695SGreg Kroah-Hartman 	go->gop_size = 0;
724866b8695SGreg Kroah-Hartman 	go->ipb = 0;
725866b8695SGreg Kroah-Hartman 	go->closed_gop = 0;
726866b8695SGreg Kroah-Hartman 	go->repeat_seqhead = 0;
727866b8695SGreg Kroah-Hartman 	go->seq_header_enable = 0;
728866b8695SGreg Kroah-Hartman 	go->gop_header_enable = 0;
729866b8695SGreg Kroah-Hartman 	go->dvd_mode = 0;
730866b8695SGreg Kroah-Hartman 	go->interlace_coding = 0;
731866b8695SGreg Kroah-Hartman 	for (i = 0; i < 4; ++i)
732859171caSJoe Perches 		go->modet[i].enable = 0;
733866b8695SGreg Kroah-Hartman 	for (i = 0; i < 1624; ++i)
734866b8695SGreg Kroah-Hartman 		go->modet_map[i] = 0;
735866b8695SGreg Kroah-Hartman 	go->audio_deliver = NULL;
736866b8695SGreg Kroah-Hartman 	go->audio_enabled = 0;
737866b8695SGreg Kroah-Hartman 
738866b8695SGreg Kroah-Hartman 	return go;
739866b8695SGreg Kroah-Hartman }
740866b8695SGreg Kroah-Hartman EXPORT_SYMBOL(go7007_alloc);
741866b8695SGreg Kroah-Hartman 
74250deb749SHans Verkuil void go7007_update_board(struct go7007 *go)
74350deb749SHans Verkuil {
7440a6ecbb4SHans Verkuil 	const struct go7007_board_info *board = go->board_info;
74550deb749SHans Verkuil 
74650deb749SHans Verkuil 	if (board->sensor_flags & GO7007_SENSOR_TV) {
74750deb749SHans Verkuil 		go->standard = GO7007_STD_NTSC;
74850deb749SHans Verkuil 		go->std = V4L2_STD_NTSC_M;
74950deb749SHans Verkuil 		go->width = 720;
75050deb749SHans Verkuil 		go->height = 480;
75150deb749SHans Verkuil 		go->sensor_framerate = 30000;
75250deb749SHans Verkuil 	} else {
75350deb749SHans Verkuil 		go->standard = GO7007_STD_OTHER;
75450deb749SHans Verkuil 		go->width = board->sensor_width;
75550deb749SHans Verkuil 		go->height = board->sensor_height;
75650deb749SHans Verkuil 		go->sensor_framerate = board->sensor_framerate;
75750deb749SHans Verkuil 	}
75850deb749SHans Verkuil 	go->encoder_v_offset = board->sensor_v_offset;
75950deb749SHans Verkuil 	go->encoder_h_offset = board->sensor_h_offset;
76050deb749SHans Verkuil }
76150deb749SHans Verkuil EXPORT_SYMBOL(go7007_update_board);
76250deb749SHans Verkuil 
763866b8695SGreg Kroah-Hartman MODULE_LICENSE("GPL v2");
764