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