From 9b5d0f1e6dd6b4a67d0851a1c5a4bcf9b0c2f258 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 17:59:15 -0300 Subject: [PATCH 001/310] V4L/DVB (5862): V4L: Add internal ioctl-like interface. This patch adds an internal ioctl-like interface which can be used in situations where a single Video4Linux device is implemented by multiple device drivers. One master device controls one or more slave devices. The slaves provide Video4Linux ioctl-like interface for the use of the master. Only a handful of ioctls are implemented at the moment. More can (and should) be added as more functionality is required. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/v4l2-int-device.c | 154 +++++++++++++++++++ include/media/v4l2-int-device.h | 210 ++++++++++++++++++++++++++ 3 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/v4l2-int-device.c create mode 100644 include/media/v4l2-int-device.h diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 10b4d4469016..d35306daac2f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -11,7 +11,8 @@ tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ + v4l2-int-device.o ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c new file mode 100644 index 000000000000..7885d9b38c92 --- /dev/null +++ b/drivers/media/video/v4l2-int-device.c @@ -0,0 +1,154 @@ +/* + * drivers/media/video/v4l2-int-device.c + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +static DEFINE_MUTEX(mutex); +static LIST_HEAD(int_list); + +static void v4l2_int_device_try_attach_all(void) +{ + struct list_head *head_master; + + list_for_each(head_master, &int_list) { + struct list_head *head_slave; + struct v4l2_int_device *m = + list_entry(head_master, struct v4l2_int_device, head); + + if (m->type != v4l2_int_type_master) + continue; + + list_for_each(head_slave, &int_list) { + struct v4l2_int_device *s = + list_entry(head_slave, + struct v4l2_int_device, head); + + if (s->type != v4l2_int_type_slave) + continue; + + /* Slave is connected? */ + if (s->u.slave->master) + continue; + + /* Slave wants to attach to master? */ + if (s->u.slave->attach_to[0] != 0 + && strncmp(m->name, s->u.slave->attach_to, + V4L2NAMESIZE)) + continue; + + if (!try_module_get(m->module)) + continue; + + if (m->u.master->attach(m, s)) { + module_put(m->module); + continue; + } + + s->u.slave->master = m; + } + } +} + +static int ioctl_sort_cmp(const void *a, const void *b) +{ + const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; + + if (d1->num > d2->num) + return 1; + + if (d1->num < d2->num) + return -1; + + return 0; +} + +int v4l2_int_device_register(struct v4l2_int_device *d) +{ + if (d->type == v4l2_int_type_slave) + sort(d->u.slave->ioctls, d->u.slave->num_ioctls, + sizeof(struct v4l2_int_ioctl_desc), + &ioctl_sort_cmp, NULL); + mutex_lock(&mutex); + list_add(&d->head, &int_list); + v4l2_int_device_try_attach_all(); + mutex_unlock(&mutex); + + return 0; +} + +void v4l2_int_device_unregister(struct v4l2_int_device *d) +{ + mutex_lock(&mutex); + list_del(&d->head); + if (d->type == v4l2_int_type_slave + && d->u.slave->master != NULL) { + d->u.slave->master->u.master->detach(d); + module_put(d->u.slave->master->module); + d->u.slave->master = NULL; + } + mutex_unlock(&mutex); +} + +static int no_such_ioctl(struct v4l2_int_device *d) +{ + return -EINVAL; +} + +/* Adapted from search_extable in extable.c. */ +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +{ + const struct v4l2_int_ioctl_desc *first = slave->ioctls; + const struct v4l2_int_ioctl_desc *last = + first + slave->num_ioctls - 1; + + while (first <= last) { + const struct v4l2_int_ioctl_desc *mid; + + mid = (last - first) / 2 + first; + + if (mid->num < cmd) + first = mid + 1; + else if (mid->num > cmd) + last = mid - 1; + else + return mid->func; + } + + return &no_such_ioctl; +} + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) +{ + return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); +} + +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) +{ + return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); +} diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h new file mode 100644 index 000000000000..2b6fc1122f6c --- /dev/null +++ b/include/media/v4l2-int-device.h @@ -0,0 +1,210 @@ +/* + * include/media/v4l2-int-device.h + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef V4L2_INT_DEVICE_H +#define V4L2_INT_DEVICE_H + +#include +#include + +#define V4L2NAMESIZE 32 + +enum v4l2_int_type { + v4l2_int_type_master = 1, + v4l2_int_type_slave +}; + +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get parallel interface clock speed for current settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the parallel interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * IOCTL wrapper functions for better type checking. + * + */ + +#define V4L2_INT_WRAPPER_0(name) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d) \ + { \ + return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d, \ + arg_type asterisk arg) \ + { \ + return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ + (void *)arg); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *, \ + arg_type asterisk)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); +V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); +V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); + +V4L2_INT_WRAPPER_0(dev_init); +V4L2_INT_WRAPPER_0(dev_exit); +V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); +V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); +V4L2_INT_WRAPPER_1(g_needs_reset, void, *); + +V4L2_INT_WRAPPER_0(reset); +V4L2_INT_WRAPPER_0(init); +V4L2_INT_WRAPPER_1(g_chip_ident, int, *); + +#endif From a5e90862114124d79e1a3f34641b00fec51d1806 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 18:04:17 -0300 Subject: [PATCH 002/310] V4L/DVB (5863): TCM825x: Add driver. Add a driver for Toshiba TCM825x VGA camera sensor. This sensor is used e.g. in Nokia N800 internet tablet. This driver uses the new V4L2 internal ioctl interface. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 2 + drivers/media/video/tcm825x.c | 942 ++++++++++++++++++++++++++++++++++ drivers/media/video/tcm825x.h | 195 +++++++ 4 files changed, 1146 insertions(+) create mode 100644 drivers/media/video/tcm825x.c create mode 100644 drivers/media/video/tcm825x.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e204e7b4028a..675c8574403e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -197,6 +197,13 @@ config VIDEO_OV7670 OV7670 VGA camera. It currently only works with the M88ALP01 controller. +config VIDEO_TCM825X + tristate "TCM825x camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a driver for the Toshiba TCM825x VGA camera sensor. + It is used for example in Nokia N800. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d35306daac2f..8f7205b558f6 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -98,6 +98,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o + obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c new file mode 100644 index 000000000000..4b973b099e59 --- /dev/null +++ b/drivers/media/video/tcm825x.c @@ -0,0 +1,942 @@ +/* + * drivers/media/video/tcm825x.c + * + * TCM825X camera sensor driver. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * Based on code from David Cohen + * + * This driver was based on ov9640 sensor driver from MontaVista + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include "tcm825x.h" + +/* + * The sensor has two fps modes: the lower one just gives half the fps + * at the same xclk than the high one. + */ +#define MAX_FPS 30 +#define MIN_FPS 8 +#define MAX_HALF_FPS (MAX_FPS / 2) +#define HIGH_FPS_MODE_LOWER_LIMIT 14 +#define DEFAULT_FPS MAX_HALF_FPS + +struct tcm825x_sensor { + const struct tcm825x_platform_data *platform_data; + struct v4l2_int_device *v4l2_int_device; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; +}; + +/* list of image formats supported by TCM825X sensor */ +const static struct v4l2_fmtdesc tcm825x_formats[] = { + { + .description = "YUYV (YUV 4:2:2), packed", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, { + /* Note: V4L2 defines RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 + * + * We interpret RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 + */ + .description = "RGB565, le", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, +}; + +#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) + +/* + * TCM825X register configuration for all combinations of pixel format and + * image size + */ +const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; +const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; +const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; +const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; +const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; +const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; + +const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; +const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; + +/* Our own specific controls */ +#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE +#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 +#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 +#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 +#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 +#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME + +/* Video controls */ +static struct vcontrol { + struct v4l2_queryctrl qc; + u16 reg; + u16 start_bit; +} video_control[] = { + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63, + .step = 1, + }, + .reg = TCM825X_AG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MRG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MBG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto White Balance", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_AWBSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Time", + .minimum = 0, + .maximum = 0x1fff, + .step = 1, + }, + .reg = TCM825X_ESRSPD_U, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Image", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_H_INV, + .start_bit = 6, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_V_INV, + .start_bit = 7, + }, + /* Private controls */ + { + { + .id = V4L2_CID_ALC, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Luminance Control", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_ALCSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_H_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Horizontal Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_HDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_V_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Vertical Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_VDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_LENS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Lens Shading Compensation", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + }, + .reg = TCM825X_LENS, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_MAX_EXPOSURE_TIME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Maximum Exposure Time", + .minimum = 0, + .maximum = 0x3, + .step = 1, + }, + .reg = TCM825X_ESRLIM, + .start_bit = 5, + }, +}; + + +const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = +{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; + +const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = +{ &yuv422, &rgb565 }; + +/* + * Read a value from a register in an TCM825X sensor device. The value is + * returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_read_reg(struct i2c_client *client, int reg) +{ + int err; + struct i2c_msg msg[2]; + u8 reg_buf, data_buf = 0; + + if (!client->adapter) + return -ENODEV; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ®_buf; + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = &data_buf; + + reg_buf = reg; + + err = i2c_transfer(client->adapter, msg, 2); + if (err < 0) + return err; + return data_buf; +} + +/* + * Write a value to a register in an TCM825X sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[2]; + + if (!client->adapter) + return -ENODEV; + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return 0; + return err; +} + +static int __tcm825x_write_reg_mask(struct i2c_client *client, + u8 reg, u8 val, u8 mask) +{ + int rc; + + /* need to do read - modify - write */ + rc = tcm825x_read_reg(client, reg); + if (rc < 0) + return rc; + + rc &= (~mask); /* Clear the masked bits */ + val &= mask; /* Enforce mask on value */ + val |= rc; + + /* write the new value to the register */ + rc = tcm825x_write_reg(client, reg, val); + if (rc) + return rc; + + return 0; +} + +#define tcm825x_write_reg_mask(client, regmask, val) \ + __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ + TCM825X_MASK((regmask))) + + +/* + * Initialize a list of TCM825X registers. + * The list of registers is terminated by the pair of values + * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_default_regs(struct i2c_client *client, + const struct tcm825x_reg *reglist) +{ + int err; + const struct tcm825x_reg *next = reglist; + + while (!((next->reg == TCM825X_REG_TERM) + && (next->val == TCM825X_VAL_TERM))) { + err = tcm825x_write_reg(client, next->reg, next->val); + if (err) { + dev_err(&client->dev, "register writing failed\n"); + return err; + } + next++; + } + + return 0; +} + +static struct vcontrol *find_vctrl(int id) +{ + int i; + + if (id < V4L2_CID_BASE) + return NULL; + + for (i = 0; i < ARRAY_SIZE(video_control); i++) + if (video_control[i].qc.id == id) + return &video_control[i]; + + return NULL; +} + +/* + * Find the best match for a requested image capture size. The best match + * is chosen as the nearest match that has the same number or fewer pixels + * as the requested size, or the smallest image size if the requested size + * has fewer pixels than the smallest image. + */ +static enum image_size tcm825x_find_size(struct v4l2_int_device *s, + unsigned int width, + unsigned int height) +{ + enum image_size isize; + unsigned long pixels = width * height; + struct tcm825x_sensor *sensor = s->priv; + + for (isize = subQCIF; isize < VGA; isize++) { + if (tcm825x_sizes[isize + 1].height + * tcm825x_sizes[isize + 1].width > pixels) { + dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); + + return isize; + } + } + + dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); + + return VGA; +} + +/* + * Configure the TCM825X for current image size, pixel format, and + * frame period. fper is the frame period (in seconds) expressed as a + * fraction. Returns zero if successful, or non-zero otherwise. The + * actual frame period is returned in fper. + */ +static int tcm825x_configure(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &sensor->pix; + enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); + struct v4l2_fract *fper = &sensor->timeperframe; + enum pixel_format pfmt; + int err; + u32 tgt_fps; + u8 val; + + /* common register initialization */ + err = tcm825x_write_default_regs( + sensor->i2c_client, sensor->platform_data->default_regs()); + if (err) + return err; + + /* configure image size */ + val = tcm825x_siz_reg[isize]->val; + dev_dbg(&sensor->i2c_client->dev, + "configuring image size %d\n", isize); + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_siz_reg[isize]->reg, val); + if (err) + return err; + + /* configure pixel format */ + switch (pix->pixelformat) { + default: + case V4L2_PIX_FMT_RGB565: + pfmt = RGB565; + break; + case V4L2_PIX_FMT_UYVY: + pfmt = YUV422; + break; + } + + dev_dbg(&sensor->i2c_client->dev, + "configuring pixel format %d\n", pfmt); + val = tcm825x_fmt_reg[pfmt]->val; + + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_fmt_reg[pfmt]->reg, val); + if (err) + return err; + + /* + * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be + * set. Frame rate will be halved from the normal. + */ + tgt_fps = fper->denominator / fper->numerator; + if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { + val = tcm825x_read_reg(sensor->i2c_client, 0x02); + val |= 0x80; + tcm825x_write_reg(sensor->i2c_client, 0x02, val); + } + + return 0; +} + +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ +#define XCLK_MIN 11900000 +#define XCLK_MAX 25000000 + +static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); + + *xclk = tgt_xclk; + + return 0; +} + +static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) +{ + if (xclk > XCLK_MAX || xclk < XCLK_MIN) + return -EINVAL; + + return 0; +} + +static int ioctl_queryctrl(struct v4l2_int_device *s, + struct v4l2_queryctrl *qc) +{ + struct vcontrol *control; + + control = find_vctrl(qc->id); + + if (control == NULL) + return -EINVAL; + + *qc = control->qc; + + return 0; +} + +static int ioctl_g_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + int val, r; + struct vcontrol *lvc; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + + val_upper = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_U)); + if (val_upper < 0) + return val_upper; + val_lower = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_L)); + if (val_lower < 0) + return val_lower; + + vc->value = ((val_upper & 0x1f) << 8) | (val_lower); + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); + if (r < 0) + return r; + val = r & TCM825X_MASK(lvc->reg); + val >>= lvc->start_bit; + + if (val < 0) + return val; + + vc->value = val; + return 0; +} + +static int ioctl_s_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + struct vcontrol *lvc; + int val = vc->value; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); + val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_U, val_upper)) + return -EIO; + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_L, val_lower)) + return -EIO; + + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + val = val << lvc->start_bit; + if (tcm825x_write_reg_mask(client, lvc->reg, val)) + return -EIO; + + return 0; +} + +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + int index = fmt->index; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= TCM825X_NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = tcm825x_formats[index].flags; + strlcpy(fmt->description, tcm825x_formats[index].description, + sizeof(fmt->description)); + fmt->pixelformat = tcm825x_formats[index].pixelformat; + + return 0; +} + +static int ioctl_try_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + enum image_size isize; + int ifmt; + struct v4l2_pix_format *pix = &f->fmt.pix; + + isize = tcm825x_find_size(s, pix->width, pix->height); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", + isize, TCM825X_NUM_CAPTURE_FORMATS); + + pix->width = tcm825x_sizes[isize].width; + pix->height = tcm825x_sizes[isize].height; + + for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) + if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) + break; + + if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) + ifmt = 0; /* Default = YUV 4:2:2 */ + + pix->pixelformat = tcm825x_formats[ifmt].pixelformat; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; + pix->sizeimage = pix->bytesperline * pix->height; + pix->priv = 0; + dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", + pix->pixelformat); + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_UYVY: + default: + pix->colorspace = V4L2_COLORSPACE_JPEG; + break; + case V4L2_PIX_FMT_RGB565: + pix->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + + return 0; +} + +static int ioctl_s_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &f->fmt.pix; + int rval; + + rval = ioctl_try_fmt_cap(s, f); + if (rval) + return rval; + + rval = tcm825x_configure(s); + + sensor->pix = *pix; + + return rval; +} + +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +static int ioctl_g_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + cparm->capability = V4L2_CAP_TIMEPERFRAME; + cparm->timeperframe = sensor->timeperframe; + + return 0; +} + +static int ioctl_s_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + int rval; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if ((timeperframe->numerator == 0) + || (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + sensor->timeperframe = *timeperframe; + + rval = tcm825x_configure(s); + + return rval; +} + +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->power_set(on); +} + +static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->needs_reset(s, buf, &sensor->pix); +} + +static int ioctl_reset(struct v4l2_int_device *s) +{ + return -EBUSY; +} + +static int ioctl_init(struct v4l2_int_device *s) +{ + return tcm825x_configure(s); +} + +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + int r; + + r = tcm825x_read_reg(sensor->i2c_client, 0x01); + if (r < 0) + return r; + if (r == 0) { + dev_err(&sensor->i2c_client->dev, "device not detected\n"); + return -EIO; + } + return 0; +} + +#define NUM_IOCTLS 17 + +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)&ioctl_dev_init }, + { vidioc_int_dev_exit_num, + (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)&ioctl_s_power }, + { vidioc_int_g_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, + { vidioc_int_s_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + { vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + { vidioc_int_reset_num, + (v4l2_int_ioctl_func *)&ioctl_reset }, + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)&ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + { vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + { vidioc_int_s_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)&ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)&ioctl_s_parm }, + { vidioc_int_queryctrl_num, + (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, +}; + +static struct v4l2_int_slave tcm825x_slave = { + .ioctls = tcm825x_ioctl_desc, + .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), +}; + +static struct tcm825x_sensor tcm825x; + +static struct v4l2_int_device tcm825x_int_device = { + .module = THIS_MODULE, + .name = TCM825X_NAME, + .priv = &tcm825x, + .type = v4l2_int_type_slave, + .u = { + .slave = &tcm825x_slave, + }, +}; + +static int tcm825x_probe(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = &tcm825x; + int rval; + + if (i2c_get_clientdata(client)) + return -EBUSY; + + sensor->platform_data = client->dev.platform_data; + + if (sensor->platform_data == NULL + && !sensor->platform_data->is_okay()) + return -ENODEV; + + sensor->v4l2_int_device = &tcm825x_int_device; + + sensor->i2c_client = client; + i2c_set_clientdata(client, sensor); + + /* Make the default capture format QVGA RGB565 */ + sensor->pix.width = tcm825x_sizes[QVGA].width; + sensor->pix.height = tcm825x_sizes[QVGA].height; + sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; + + rval = v4l2_int_device_register(sensor->v4l2_int_device); + if (rval) + i2c_set_clientdata(client, NULL); + + return rval; +} + +static int __exit tcm825x_remove(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = i2c_get_clientdata(client); + + if (!client->adapter) + return -ENODEV; /* our client isn't attached */ + + v4l2_int_device_unregister(sensor->v4l2_int_device); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static struct i2c_driver tcm825x_i2c_driver = { + .driver = { + .name = TCM825X_NAME, + }, + .probe = &tcm825x_probe, + .remove = __exit_p(&tcm825x_remove), +}; + +static struct tcm825x_sensor tcm825x = { + .timeperframe = { + .numerator = 1, + .denominator = DEFAULT_FPS, + }, +}; + +static int __init tcm825x_init(void) +{ + int rval; + int i = 0; + + /* Just an experiment --- don't use *_cb functions yet. */ + tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); + BUG_ON(i >= NUM_IOCTLS); + + rval = i2c_add_driver(&tcm825x_i2c_driver); + if (rval) + printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", + __FUNCTION__); + + return rval; +} + +static void __exit tcm825x_exit(void) +{ + i2c_del_driver(&tcm825x_i2c_driver); +} + +/* + * FIXME: Menelaus isn't ready (?) at module_init stage, so use + * late_initcall for now. + */ +late_initcall(tcm825x_init); +module_exit(tcm825x_exit); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("TCM825x camera sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h new file mode 100644 index 000000000000..d6471ec40bc5 --- /dev/null +++ b/drivers/media/video/tcm825x.h @@ -0,0 +1,195 @@ +/* + * drivers/media/video/tcm825x.h + * + * Register definitions for the TCM825X CameraChip. + * + * Author: David Cohen (david.cohen@indt.org.br) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * This file was based on ov9640.h from MontaVista + */ + +#ifndef TCM825X_H +#define TCM825X_H + +#include + +#include + +#define TCM825X_NAME "tcm825x" + +#define TCM825X_MASK(x) x & 0x00ff +#define TCM825X_ADDR(x) (x & 0xff00) >> 8 + +/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */ +#define TCM825X_I2C_ADDR 0x3d + +/* + * define register offsets for the TCM825X sensor chip + * OFFSET(8 bits) + MASK(8 bits) + * MASK bit 4 and 3 are used when the register uses more than one address + */ +#define TCM825X_FPS 0x0280 +#define TCM825X_ACF 0x0240 +#define TCM825X_DOUTBUF 0x020C +#define TCM825X_DCLKP 0x0202 +#define TCM825X_ACFDET 0x0201 +#define TCM825X_DOUTSW 0x0380 +#define TCM825X_DATAHZ 0x0340 +#define TCM825X_PICSIZ 0x033c +#define TCM825X_PICFMT 0x0302 +#define TCM825X_V_INV 0x0480 +#define TCM825X_H_INV 0x0440 +#define TCM825X_ESRLSW 0x0430 +#define TCM825X_V_LENGTH 0x040F +#define TCM825X_ALCSW 0x0580 +#define TCM825X_ESRLIM 0x0560 +#define TCM825X_ESRSPD_U 0x051F +#define TCM825X_ESRSPD_L 0x06FF +#define TCM825X_AG 0x07FF +#define TCM825X_ESRSPD2 0x06FF +#define TCM825X_ALCMODE 0x0830 +#define TCM825X_ALCH 0x080F +#define TCM825X_ALCL 0x09FF +#define TCM825X_AWBSW 0x0A80 +#define TCM825X_MRG 0x0BFF +#define TCM825X_MBG 0x0CFF +#define TCM825X_GAMSW 0x0D80 +#define TCM825X_HDTG 0x0EFF +#define TCM825X_VDTG 0x0FFF +#define TCM825X_HDTCORE 0x10F0 +#define TCM825X_VDTCORE 0x100F +#define TCM825X_CONT 0x11FF +#define TCM825X_BRIGHT 0x12FF +#define TCM825X_VHUE 0x137F +#define TCM825X_UHUE 0x147F +#define TCM825X_VGAIN 0x153F +#define TCM825X_UGAIN 0x163F +#define TCM825X_UVCORE 0x170F +#define TCM825X_SATU 0x187F +#define TCM825X_MHMODE 0x1980 +#define TCM825X_MHLPFSEL 0x1940 +#define TCM825X_YMODE 0x1930 +#define TCM825X_MIXHG 0x1907 +#define TCM825X_LENS 0x1A3F +#define TCM825X_AGLIM 0x1BE0 +#define TCM825X_LENSRPOL 0x1B10 +#define TCM825X_LENSRGAIN 0x1B0F +#define TCM825X_ES100S 0x1CFF +#define TCM825X_ES120S 0x1DFF +#define TCM825X_DMASK 0x1EC0 +#define TCM825X_CODESW 0x1E20 +#define TCM825X_CODESEL 0x1E10 +#define TCM825X_TESPIC 0x1E04 +#define TCM825X_PICSEL 0x1E03 +#define TCM825X_HNUM 0x20FF +#define TCM825X_VOUTPH 0x287F +#define TCM825X_ESROUT 0x327F +#define TCM825X_ESROUT2 0x33FF +#define TCM825X_AGOUT 0x34FF +#define TCM825X_DGOUT 0x353F +#define TCM825X_AGSLOW1 0x39C0 +#define TCM825X_FLLSMODE 0x3930 +#define TCM825X_FLLSLIM 0x390F +#define TCM825X_DETSEL 0x3AF0 +#define TCM825X_ACDETNC 0x3A0F +#define TCM825X_AGSLOW2 0x3BC0 +#define TCM825X_DG 0x3B3F +#define TCM825X_REJHLEV 0x3CFF +#define TCM825X_ALCLOCK 0x3D80 +#define TCM825X_FPSLNKSW 0x3D40 +#define TCM825X_ALCSPD 0x3D30 +#define TCM825X_REJH 0x3D03 +#define TCM825X_SHESRSW 0x3E80 +#define TCM825X_ESLIMSEL 0x3E40 +#define TCM825X_SHESRSPD 0x3E30 +#define TCM825X_ELSTEP 0x3E0C +#define TCM825X_ELSTART 0x3E03 +#define TCM825X_AGMIN 0x3FFF +#define TCM825X_PREGRG 0x423F +#define TCM825X_PREGBG 0x433F +#define TCM825X_PRERG 0x443F +#define TCM825X_PREBG 0x453F +#define TCM825X_MSKBR 0x477F +#define TCM825X_MSKGR 0x487F +#define TCM825X_MSKRB 0x497F +#define TCM825X_MSKGB 0x4A7F +#define TCM825X_MSKRG 0x4B7F +#define TCM825X_MSKBG 0x4C7F +#define TCM825X_HDTCSW 0x4D80 +#define TCM825X_VDTCSW 0x4D40 +#define TCM825X_DTCYL 0x4D3F +#define TCM825X_HDTPSW 0x4E80 +#define TCM825X_VDTPSW 0x4E40 +#define TCM825X_DTCGAIN 0x4E3F +#define TCM825X_DTLLIMSW 0x4F10 +#define TCM825X_DTLYLIM 0x4F0F +#define TCM825X_YLCUTLMSK 0x5080 +#define TCM825X_YLCUTL 0x503F +#define TCM825X_YLCUTHMSK 0x5180 +#define TCM825X_YLCUTH 0x513F +#define TCM825X_UVSKNC 0x527F +#define TCM825X_UVLJ 0x537F +#define TCM825X_WBGMIN 0x54FF +#define TCM825X_WBGMAX 0x55FF +#define TCM825X_WBSPDUP 0x5603 +#define TCM825X_ALLAREA 0x5820 +#define TCM825X_WBLOCK 0x5810 +#define TCM825X_WB2SP 0x580F +#define TCM825X_KIZUSW 0x5920 +#define TCM825X_PBRSW 0x5910 +#define TCM825X_ABCSW 0x5903 +#define TCM825X_PBDLV 0x5AFF +#define TCM825X_PBC1LV 0x5BFF + +#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1) + +#define TCM825X_BYTES_PER_PIXEL 2 + +#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */ +#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */ + +/* define a structure for tcm825x register initialization values */ +struct tcm825x_reg { + u8 val; + u16 reg; +}; + +enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA }; +enum pixel_format { YUV422 = 0, RGB565 }; +#define NUM_IMAGE_SIZES 6 +#define NUM_PIXEL_FORMATS 2 + +struct capture_size { + unsigned long width; + unsigned long height; +}; + +struct tcm825x_platform_data { + /* Is the sensor usable? Doesn't yet mean it's there, but you + * can try! */ + int (*is_okay)(void); + /* Set power state, zero is off, non-zero is on. */ + int (*power_set)(int power); + /* Default registers written after power-on or reset. */ + const struct tcm825x_reg *(*default_regs)(void); + int (*needs_reset)(struct v4l2_int_device *s, void *buf, + struct v4l2_pix_format *fmt); +}; + +/* Array of image sizes supported by TCM825X. These must be ordered from + * smallest image size to largest. + */ +const static struct capture_size tcm825x_sizes[] = { + { 128, 96 }, /* subQCIF */ + { 160, 120 }, /* QQVGA */ + { 176, 144 }, /* QCIF */ + { 320, 240 }, /* QVGA */ + { 352, 288 }, /* CIF */ + { 640, 480 }, /* VGA */ +}; + +#endif /* ifndef TCM825X_H */ From baa05e4b454fa7d87f9a41a4bbc1f749c113ff3a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:26:34 -0300 Subject: [PATCH 003/310] V4L/DVB (5881): ivtv: init channel for NTSC_M_JP standard. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index d73d433a4ff6..622af634104e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1154,8 +1154,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ - if (itv->std & V4L2_STD_NTSC_M) { - /* Why on earth? */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { vf.frequency = 1076; /* ch. 4 67250*16/1000 */ } From 63116febb9233743279a05be510ab8524f5f6242 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 20 Jul 2007 13:12:51 -0300 Subject: [PATCH 004/310] V4L/DVB (5883): V4L: Fix a compile warning on non-32-bit machines. Fix a compile warning on non-32-bit machines in v4l2-int-device.h. Add internal ioctl interface fallback function for ioctls with one argument. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 28 ++++++++++++++++++--------- include/media/v4l2-int-device.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7885d9b38c92..aa2a8156338d 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -115,13 +115,9 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) mutex_unlock(&mutex); } -static int no_such_ioctl(struct v4l2_int_device *d) -{ - return -EINVAL; -} - /* Adapted from search_extable in extable.c. */ -static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, + v4l2_int_ioctl_func *no_such_ioctl) { const struct v4l2_int_ioctl_desc *first = slave->ioctls; const struct v4l2_int_ioctl_desc *last = @@ -140,15 +136,29 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) return mid->func; } - return &no_such_ioctl; + return no_such_ioctl; +} + +static int no_such_ioctl_0(struct v4l2_int_device *d) +{ + return -EINVAL; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { - return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); + return ((v4l2_int_ioctl_func_0 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); +} + +static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) +{ + return -EINVAL; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { - return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); + return ((v4l2_int_ioctl_func_1 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 2b6fc1122f6c..deb28ce6685d 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -170,7 +170,7 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); arg_type asterisk arg) \ { \ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ - (void *)arg); \ + (void *)(unsigned long)arg); \ } \ \ static inline struct v4l2_int_ioctl_desc \ From 18b548ca580838a2cc5813a941e6dab28660bb22 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 17 Jul 2007 18:29:41 -0300 Subject: [PATCH 005/310] V4L/DVB (5884): zr36067: clean up debug function Debugging cleanups to the zr36067 driver: * Use module_param_named() to declare the debug parameter, so we can use a single global variable to handle the debug level. This makes the driver a bit smaller (by 648 bytes on x86_64), thanks to one less level of indirection on every use. * Change the debug parameter sysfs permissions, so that the debug level can be adjusted at runtime, as is done in many other media/video drivers. * The debug level is between 0 and 5, not 0 and 4. * Move the zr_debug export and dprintk macro definition to a header file so that we don't have to define them in each source file. * Simplify a duplicate test on zr_debug. Note that zr_debug was subsequently renamed to debug_zr36067 to avoid possible conflicts with other Zoran device drivers, on a suggestion by Trent Piepho. Signed-off-by: Jean Delvare Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 19 ++++++------------- drivers/media/video/zoran_card.h | 8 ++++++++ drivers/media/video/zoran_device.c | 17 +++++------------ drivers/media/video/zoran_driver.c | 20 +++++--------------- drivers/media/video/zoran_procfs.c | 9 +-------- 5 files changed, 25 insertions(+), 48 deletions(-) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 73162a3a61dd..8e12ff80550d 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -145,10 +145,9 @@ module_param(pass_through, int, 0); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); -static int debug = 1; -int *zr_debug = &debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +int zr36067_debug = 1; +module_param_named(debug, zr36067_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-5)"); MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); @@ -161,12 +160,6 @@ static struct pci_device_id zr36067_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - int zoran_num; /* number of Buzs in use */ struct zoran zoran[BUZ_MAX]; @@ -1075,7 +1068,7 @@ test_interrupts (struct zoran *zr) if (timeout) { dprintk(1, ": time spent: %d\n", 1 * HZ - timeout); } - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); btwrite(icr, ZR36057_ICR); } @@ -1158,7 +1151,7 @@ zr36057_init (struct zoran *zr) goto exit_unregister; zoran_init_hardware(zr); - if (*zr_debug > 2) + if (zr36067_debug > 2) detect_guest_activity(zr); test_interrupts(zr); if (!pass_through) { @@ -1620,7 +1613,7 @@ init_dc10_cards (void) } /* random nonsense */ - dprintk(5, KERN_DEBUG "Jotti is een held!\n"); + dprintk(6, KERN_DEBUG "Jotti is een held!\n"); /* some mainboards might not do PCI-PCI data transfer well */ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) { diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h index ad997c30bee5..8444ca0a5f3f 100644 --- a/drivers/media/video/zoran_card.h +++ b/drivers/media/video/zoran_card.h @@ -30,6 +30,14 @@ #ifndef __ZORAN_CARD_H__ #define __ZORAN_CARD_H__ +extern int zr36067_debug; + +#define dprintk(num, format, args...) \ + do { \ + if (zr36067_debug >= num) \ + printk(format, ##args); \ + } while (0) + /* Anybody who uses more than four? */ #define BUZ_MAX 4 extern int zoran_num; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index ba2f4ed29483..dc1ec20fb266 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -52,6 +52,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_device.h" +#include "zoran_card.h" #define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \ ZR36057_ISR_GIRQ1 | \ @@ -59,14 +60,6 @@ extern const struct zoran_format zoran_formats[]; -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - static int lml33dpath = 0; /* 1 will use digital path in capture * mode instead of analog. It can be * used for picture adjustments using @@ -174,7 +167,7 @@ post_office_read (struct zoran *zr, static void dump_guests (struct zoran *zr) { - if (*zr_debug > 2) { + if (zr36067_debug > 2) { int i, guest[8]; for (i = 1; i < 8; i++) { // Don't read jpeg codec here @@ -1271,7 +1264,7 @@ error_handler (struct zoran *zr, zr->num_errors++; /* Report error */ - if (*zr_debug > 1 && zr->num_errors <= 8) { + if (zr36067_debug > 1 && zr->num_errors <= 8) { long frame; frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; @@ -1531,7 +1524,7 @@ zoran_irq (int irq, if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - if (*zr_debug > 1 && + if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) { printk(KERN_INFO "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", @@ -1568,7 +1561,7 @@ zoran_irq (int irq, zr->JPEG_missed; } - if (*zr_debug > 2 && zr->frame_num < 6) { + if (zr36067_debug > 2 && zr->frame_num < 6) { int i; printk("%s: seq=%ld stat_com:", ZR_DEVNAME(zr), zr->jpg_seq_num); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 72a037b75d63..377bb2d11ffd 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -200,14 +200,6 @@ const struct zoran_format zoran_formats[] = { // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - extern int v4l_nbufs; extern int v4l_bufsize; extern int jpg_nbufs; @@ -1106,12 +1098,10 @@ jpg_sync (struct file *file, frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; /* buffer should now be in BUZ_STATE_DONE */ - if (*zr_debug > 0) - if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR - "%s: jpg_sync() - internal state error\n", - ZR_DEVNAME(zr)); + if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) + dprintk(2, + KERN_ERR "%s: jpg_sync() - internal state error\n", + ZR_DEVNAME(zr)); *bs = zr->jpg_buffers.buffer[frame].bs; bs->frame = frame; @@ -1389,7 +1379,7 @@ zoran_close (struct inode *inode, /* disable interrupts */ btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); /* Overlay off */ diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 446ae8d5c3df..328ed6e7ac6a 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -48,14 +48,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_procfs.h" - -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) +#include "zoran_card.h" #ifdef CONFIG_PROC_FS struct procfs_params_zr36067 { From 60e3cac47a442fae74d3429f706350229623bcce Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 17 Jul 2007 18:29:42 -0300 Subject: [PATCH 006/310] V4L/DVB (5885): zr36067: Fix problems with module parameters Add permissions to all the module parameters so they can be queried and set (when possible) via sysfs. Add description for the vidmem parameter. Change the video_nr parameter to an array, so that the video number can be specified when a user has more than one card. The driver would try to give all cards the same number otherwise, which will fail for all cards after the first. The default_input option would only allow values of 0 or 1, contrary to the description. Allow values up to the number of inputs defined for the card. Add description of lock_norm's different behavior for 1 and >1. Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 45 ++++++++++++++++++------------ drivers/media/video/zoran_device.c | 2 +- drivers/media/video/zoran_driver.c | 4 +-- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 8e12ff80550d..48da36a15fca 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -64,15 +64,15 @@ extern const struct zoran_format zoran_formats[]; static int card[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(card, int, NULL, 0); +module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "The type of card"); static int encoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(encoder, int, NULL, 0); +module_param_array(encoder, int, NULL, 0444); MODULE_PARM_DESC(encoder, "i2c TV encoder"); static int decoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(decoder, int, NULL, 0); +module_param_array(decoder, int, NULL, 0444); MODULE_PARM_DESC(decoder, "i2c TV decoder"); /* @@ -84,29 +84,31 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder"); */ static unsigned long vidmem = 0; /* Video memory base address */ -module_param(vidmem, ulong, 0); +module_param(vidmem, ulong, 0444); +MODULE_PARM_DESC(vidmem, "Default video memory base address"); /* Default input and video norm at startup of the driver. */ -static int default_input = 0; /* 0=Composite, 1=S-Video */ -module_param(default_input, int, 0); +static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */ +module_param(default_input, uint, 0444); MODULE_PARM_DESC(default_input, "Default input (0=Composite, 1=S-Video, 2=Internal)"); static int default_mux = 1; /* 6 Eyes input selection */ -module_param(default_mux, int, 0); +module_param(default_mux, int, 0644); MODULE_PARM_DESC(default_mux, "Default 6 Eyes mux setting (Input selection)"); static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */ -module_param(default_norm, int, 0); +module_param(default_norm, int, 0444); MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "video device number"); +/* /dev/videoN, -1 for autodetect */ +static int video_nr[BUZ_MAX] = {-1, -1, -1, -1}; +module_param_array(video_nr, int, NULL, 0444); +MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); /* Number and size of grab buffers for Video 4 Linux @@ -127,21 +129,21 @@ MODULE_PARM_DESC(video_nr, "video device number"); int v4l_nbufs = 2; int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0); +module_param(v4l_nbufs, int, 0644); MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0); +module_param(v4l_bufsize, int, 0644); MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); int jpg_nbufs = 32; int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0); +module_param(jpg_nbufs, int, 0644); MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0); +module_param(jpg_bufsize, int, 0644); MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); int pass_through = 0; /* 1=Pass through TV signal when device is not used */ /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ -module_param(pass_through, int, 0); +module_param(pass_through, int, 0644); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); @@ -1114,7 +1116,14 @@ zr36057_init (struct zoran *zr) zr->timing = zr->card.tvn[zr->norm]; } - zr->input = default_input = (default_input ? 1 : 0); + if (default_input > zr->card.inputs-1) { + dprintk(1, + KERN_WARNING + "%s: default_input value %d out of range (0-%d)\n", + ZR_DEVNAME(zr), default_input, zr->card.inputs-1); + default_input = 0; + } + zr->input = default_input; /* Should the following be reset at every open ? */ zr->hue = 32768; @@ -1146,7 +1155,7 @@ zr36057_init (struct zoran *zr) */ memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template)); strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); - err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr); + err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); if (err < 0) goto exit_unregister; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index dc1ec20fb266..68c7c505587e 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -69,7 +69,7 @@ static int lml33dpath = 0; /* 1 will use digital path in capture * load on Bt819 input, there will be * some image imperfections */ -module_param(lml33dpath, bool, 0); +module_param(lml33dpath, bool, 0644); MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 377bb2d11ffd..4dbe2d449b50 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -207,8 +207,8 @@ extern int jpg_bufsize; extern int pass_through; static int lock_norm = 0; /* 1=Don't change TV standard (norm) */ -module_param(lock_norm, int, 0); -MODULE_PARM_DESC(lock_norm, "Users can't change norm"); +module_param(lock_norm, int, 0644); +MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); #ifdef CONFIG_VIDEO_V4L2 /* small helper function for calculating buffersizes for v4l2 From d3c35acf2455fe354bdd00085511bef6bd6d52f1 Mon Sep 17 00:00:00 2001 From: Rasmus Rohde Date: Sat, 21 Jul 2007 15:37:35 -0300 Subject: [PATCH 007/310] V4L/DVB (5897): dtt200u: add support for the Miglia TVMini USB DVB-T adapter add code for autodetection and firmware download to the Miglia TVMini USB DVB-T adapter. After firmware download, the device re-registers using the WT220U_ZL0353_WARM usb id. Signed-off-by: Rasmus Rohde Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtt200u.c | 28 ++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 7dbe14321019..d86cf9bee91c 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties; static struct dvb_usb_device_properties wt220u_fc_properties; static struct dvb_usb_device_properties wt220u_properties; static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { } }; +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", @@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4dfab02a8a0d..78ea3b566ffc 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -34,6 +34,7 @@ #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 +#define USB_VID_MIGLIA 0x18f3 #define USB_VID_MSI 0x0db0 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 From 32db775452818656d5fd8fd8b0f54425f5cfc177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 09:29:43 -0300 Subject: [PATCH 008/310] V4L/DVB (5902): Add ivtv-fb framebuffer driver. Add the ivtv-fb framebuffer driver for cx23415 devices (currently only the Hauppauge PVR-350 cards). This makes it possible to use the On-Screen Display functionality of these cards, either for menus during MPEG playback, or as a console or X display. Signed-off-by: Kevin Thayer Signed-off-by: Chris Kennedy Signed-off-by: Hans Verkuil Signed-off-by: John P Harvey Signed-off-by: Ian Armstrong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 16 + drivers/media/video/ivtv/Makefile | 1 + drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 26 +- drivers/media/video/ivtv/ivtv-fb.c | 1215 ++++++++++++++++++++++++ include/media/ivtv-fb.h | 35 + 6 files changed, 1283 insertions(+), 25 deletions(-) create mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 include/media/ivtv-fb.h diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index e43beb2c9cbf..399f231abb96 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -25,3 +25,19 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. + +config VIDEO_IVTV_FB + tristate "Conexant cx23415 framebuffer support" + depends on VIDEO_IVTV && FB && EXPERIMENTAL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is a framebuffer driver for the Conexant cx23415 MPEG + encoder/decoder. + + This is used in the Hauppauge PVR-350 card. There is a driver + homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtv-fb. diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 7e95148fbf4f..90e2d1270561 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,3 +5,4 @@ ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-video.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o +obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 622af634104e..81cbaf7dd51c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -95,8 +95,14 @@ const u32 yuv_offset[4] = { /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static int cardtype_c = 1; static int tuner_c = 1; @@ -1242,8 +1248,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); + spin_lock(&ivtv_cards_lock); kfree(ivtv_cards[ivtv_cards_active]); ivtv_cards[ivtv_cards_active] = NULL; + spin_unlock(&ivtv_cards_lock); return retval; } @@ -1346,6 +1354,7 @@ static void module_cleanup(void) pci_unregister_driver(&ivtv_pci_driver); + spin_lock(&ivtv_cards_lock); for (i = 0; i < ivtv_cards_active; i++) { if (ivtv_cards[i] == NULL) continue; @@ -1354,6 +1363,7 @@ static void module_cleanup(void) } kfree(ivtv_cards[i]); } + spin_unlock(&ivtv_cards_lock); } /* Note: These symbols are exported because they are used by the ivtv-fb @@ -1361,6 +1371,7 @@ static void module_cleanup(void) EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); EXPORT_SYMBOL(ivtv_cards); +EXPORT_SYMBOL(ivtv_cards_lock); EXPORT_SYMBOL(ivtv_api); EXPORT_SYMBOL(ivtv_vapi); EXPORT_SYMBOL(ivtv_vapi_result); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8abb34a35816..8fe9d9c7a18e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -89,11 +89,9 @@ extern const u32 yuv_offset[4]; -/* Maximum ivtv driver instances. - Based on 6 PVR500s each with two PVR15s... - TODO: make this dynamic. I believe it is only a global in order to support - ivtv-fb. There must be a better way to do that. */ -#define IVTV_MAX_CARDS 12 +/* Maximum ivtv driver instances. Some people have a huge number of + capture cards, so set this to a high value. */ +#define IVTV_MAX_CARDS 32 /* Supported cards */ #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ @@ -303,28 +301,10 @@ extern const u32 yuv_offset[4]; #define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) #define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ #define MPEG_FRAME_TYPE_IFRAME 1 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c new file mode 100644 index 000000000000..8e9bd75fc2bf --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -0,0 +1,1215 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-fileops.h" +#include "ivtv-mailbox.h" +#include "ivtv-cards.h" +#include + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8,16,32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Timing info for modes */ + u32 pixclock; + u32 hlimit; + u32 vlimit; + + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - itv->osd_info->video_rbase; + osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + itv->osd_info->display_width = osd->pixel_stride; + itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; + itv->osd_info->set_osd_coords_x += osd->x; + itv->osd_info->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + itv->osd_info->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + IVTV_FB_WARN( + "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " + "only %d available\n", + (dest_offset + count), itv->osd_info->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + + if (count & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN( + "Invalid userspace pointer!!! 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN( + "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc=0; + + switch (cmd) { + + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg (0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->lastVsyncFrame; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: { + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + finish_wait (&itv->vsync_waitq, &wait); + return rc; + } + + case IVTVFB_IOCTL_PREP_FRAME: { + struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + else /* RGB */ + write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + + /* Set the color mode + Although rare, occasionally things go wrong. The extra mode + change seems to help... */ + + switch (var->bits_per_pixel) { + case 8: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + break; + case 32: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + break; + case 16: + switch (var->green.length) { + case 4: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + break; + case 5: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + break; + case 6: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + itv->osd_info->bits_per_pixel = var->bits_per_pixel; + itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin ++; + if (!var->left_margin) var->left_margin ++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_INFO("=== Display mode change ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = itv->osd_info->video_pbase; + fix->smem_len = itv->osd_info->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = itv->osd_info->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + break; + case 5: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + default: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + } + else { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || + var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != + itv->osd_info->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", + var->xres,var->yres, var->xres_virtual,var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", + var->xres,var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, + var->yoffset,var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; + var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + var->pixclock = itv->osd_info->pixclock; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock /= 2; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); + + IVTV_FB_INFO("=== Validated display mode ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + return _ivtvfb_check_var (var,itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg (osd_pan_index,0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix (itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *) info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + } + else { + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + } + + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + int max_height; + struct v4l2_rect start_window; + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + itv->osd_info->pixclock = 84316; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 591; + } + else { + itv->osd_info->pixclock = 83926; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 495; + } + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + itv->osd_info->bits_per_pixel = osd_depth; + itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left --; + + start_window.left = + osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + itv->osd_info->display_byte_stride = + start_window.width * itv->osd_info->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if ( osd_yres > max_height) osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else { + if (itv->is_50hz) + start_window.height = osd_compat ? max_height : 480; + else + start_window.height = osd_compat ? max_height : 400; + } + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper --; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + itv->osd_info->display_width = start_window.width; + itv->osd_info->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; + itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; + itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; + itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + itv->osd_info->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + + /* Generate valid fb_info */ + + itv->osd_info->ivtvfb_info.node = -1; + itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + itv->osd_info->ivtvfb_info.par = itv; + itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; + itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; + itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; + itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; + itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; + itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + + if (!itv->osd_info->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + itv->osd_info->video_buffer_size = 1704960; + + itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + + if (!itv->osd_info->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + itv->osd_info->video_pbase, itv->osd_info->video_vbase, + itv->osd_info->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); + itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; + itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; + itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, + itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", + (unsigned int)itv->osd_info->fb_start_aligned_physaddr, + (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + } + } +#endif /* CONFIG_MTRR */ + + /* Blank the entire osd. */ + memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + /* Release cmap */ + if (itv->osd_info->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (itv->osd_info->ivtvfb_info.pseudo_palette) + kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, + (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); +#endif /* CONFIG_MTRR */ + + kfree(itv->osd_info); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card (struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io (itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode (itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h new file mode 100644 index 000000000000..902b2f3d3cb6 --- /dev/null +++ b/include/media/ivtv-fb.h @@ -0,0 +1,35 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_IVTV_FB_H +#define _LINUX_IVTV_FB_H + +/* Framebuffer external API */ + +struct ivtvfb_ioctl_dma_host_to_ivtv_args { + void __user *source; + unsigned long dest_offset; + int count; +}; + +/* Framebuffer ioctls should use the range 1 - 28 */ +#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) + +#endif From be383bd312c4defab8bd4bde8c06fea5bfe0996b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:16:03 -0300 Subject: [PATCH 009/310] V4L/DVB (5904): ivtv-fb: cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 439 ++++++++++++++--------------- 1 file changed, 204 insertions(+), 235 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 8e9bd75fc2bf..01cd65328e8a 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -3,7 +3,7 @@ This module presents the cx23415 OSD (onscreen display) framebuffer memory as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp mode, there is a choice of a three color depths (12, 15 or 16 bits), but no local alpha. The colorspace is selectable between rgb & yuv. Depending on the TV standard configured in the ivtv module at load time, @@ -111,7 +111,7 @@ MODULE_PARM_DESC(osd_laced, "\t\t\tdefault off"); MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8,16,32\n" + "Bits per pixel - 8, 16, 32\n" "\t\t\tdefault 8"); MODULE_PARM_DESC(osd_upper, @@ -232,12 +232,13 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, static int ivtv_fb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { + struct osd_info *oi = itv->osd_info; u32 data[CX2341X_MBOX_MAX_DATA]; ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - osd->offset = data[0] - itv->osd_info->video_rbase; - osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; osd->pixel_stride = data[1]; osd->lines = data[2]; osd->x = data[3]; @@ -247,20 +248,21 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { - itv->osd_info->display_width = osd->pixel_stride; - itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; - itv->osd_info->set_osd_coords_x += osd->x; - itv->osd_info->set_osd_coords_y = osd->y; + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + itv->osd_info->video_rbase, + osd->offset + oi->video_rbase, osd->pixel_stride, osd->lines, osd->x, osd->y); } static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { - int osd_height_limit = itv->is_50hz ? 576 : 480; /* Only fail if resolution too high, otherwise fudge the start coords. */ @@ -269,13 +271,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -344,7 +346,8 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -356,31 +359,28 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, un /* Check Total FB Size */ if ((dest_offset + count) > itv->osd_info->video_buffer_size) { - IVTV_FB_WARN( - "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " - "only %d available\n", - (dest_offset + count), itv->osd_info->video_buffer_size); + IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, itv->osd_info->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN( - "Invalid userspace pointer!!! 0x%08lx\n", + IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN( - "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -397,17 +397,16 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar { DEFINE_WAIT(wait); struct ivtv *itv = (struct ivtv *)info->par; - int rc=0; + int rc = 0; switch (cmd) { - case FBIOGET_VBLANK: { struct fb_vblank vblank; u32 trace; vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC; - trace = read_reg (0x028c0) >> 16; + trace = read_reg(0x028c0) >> 16; if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; @@ -419,12 +418,11 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar return 0; } - case FBIO_WAITFORVSYNC: { + case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; - finish_wait (&itv->vsync_waitq, &wait); + finish_wait(&itv->vsync_waitq, &wait); return rc; - } case IVTVFB_IOCTL_PREP_FRAME: { struct ivtvfb_ioctl_dma_host_to_ivtv_args args; @@ -437,7 +435,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); return -EINVAL; } return 0; @@ -447,7 +445,6 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { - struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; @@ -455,9 +452,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Select color space */ if (var->nonstd) /* YUV */ - write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); else /* RGB */ - write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); /* Set the color mode Although rare, occasionally things go wrong. The extra mode @@ -525,8 +522,8 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.height = var->yres; /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) var->upper_margin ++; - if (!var->left_margin) var->left_margin ++; + if (!var->upper_margin) var->upper_margin++; + if (!var->left_margin) var->left_margin++; ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; @@ -535,48 +532,36 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_INFO("=== Display mode change ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, - var->bits_per_pixel); + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } - - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { - IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + struct osd_info *oi = itv->osd_info; + + IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); - fix->smem_start = itv->osd_info->video_pbase; - fix->smem_len = itv->osd_info->video_buffer_size; + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 1; fix->ypanstep = 1; fix->ywrapstep = 0; - fix->line_length = itv->osd_info->display_byte_stride; + fix->line_length = oi->display_byte_stride; fix->accel = FB_ACCEL_NONE; return 0; } @@ -586,14 +571,15 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; int osd_height_limit = itv->is_50hz ? 576 : 480; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -609,11 +595,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { + var->transp.offset = 0; + var->transp.length = 0; + /* To find out the true mode, check green length */ switch (var->green.length) { case 4: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 8; var->red.length = 4; var->green.offset = 4; @@ -622,8 +609,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 4; break; case 5: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; @@ -632,8 +617,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 5; break; default: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; @@ -644,33 +627,34 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } /* Check the resolution */ if (osd_compat) { - if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || - var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != - itv->osd_info->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", - var->xres,var->yres, var->xres_virtual,var->yres_virtual); + if (var->xres != oi->ivtvfb_defined.xres || + var->yres != oi->ivtvfb_defined.yres || + var->xres_virtual != oi->ivtvfb_defined.xres_virtual || + var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", - var->xres,var->yres); + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); return -EINVAL; } /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -680,43 +664,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, - var->yoffset,var->yres_virtual); + IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -732,8 +716,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; - var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + var->right_margin = oi->hlimit - var->left_margin - var->xres; + var->lower_margin = oi->vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -742,45 +726,29 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = itv->osd_info->pixclock; + var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) var->pixclock /= 2; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); - - IVTV_FB_INFO("=== Validated display mode ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } - - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); - return _ivtvfb_check_var (var,itv); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); } static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -789,7 +757,7 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf struct ivtv *itv = (struct ivtv *) info->par; osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg (osd_pan_index,0x02A0C); + write_reg(osd_pan_index, 0x02A0C); /* Pass this info back the yuv handler */ itv->yuv_info.osd_x_pan = var->xoffset; @@ -804,11 +772,11 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix (itv, &info->fix); + ivtvfb_get_fix(itv, &info->fix); return rc; } @@ -817,7 +785,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { u32 color, *palette; - struct ivtv *itv = (struct ivtv *) info->par; + struct ivtv *itv = (struct ivtv *)info->par; if (regno >= info->cmap.len) return -EINVAL; @@ -826,34 +794,32 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (info->var.bits_per_pixel <= 8) { write_reg(regno, 0x02a30); write_reg(color, 0x02a34); + return 0; } - else { - if (regno >= 16) - return -EINVAL; + if (regno >= 16) + return -EINVAL; - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; } - palette[regno] = color; } - + palette[regno] = color; return 0; } @@ -863,7 +829,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -898,27 +864,28 @@ static struct fb_ops ivtvfb_ops = { /* Setup our initial video mode */ static int ivtvfb_init_vidmode(struct ivtv *itv) { - int max_height; + struct osd_info *oi = itv->osd_info; struct v4l2_rect start_window; + int max_height; /* Set base references for mode calcs. */ if (itv->is_50hz) { - itv->osd_info->pixclock = 84316; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 591; + oi->pixclock = 84316; + oi->hlimit = 776; + oi->vlimit = 591; } else { - itv->osd_info->pixclock = 83926; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 495; + oi->pixclock = 83926; + oi->hlimit = 776; + oi->vlimit = 495; } /* Color mode */ if (osd_compat) osd_depth = 32; if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; - itv->osd_info->bits_per_pixel = osd_depth; - itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; /* Horizontal size & position */ @@ -937,97 +904,93 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + IVTV_FB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_left --; + osd_left--; - start_window.left = - osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - itv->osd_info->display_byte_stride = - start_window.width * itv->osd_info->bytes_per_pixel; + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; /* Vertical size & position */ max_height = itv->is_50hz ? 576 : 480; - if ( osd_yres > max_height) osd_yres = max_height; + if (osd_yres > max_height) + osd_yres = max_height; if (osd_yres) start_window.height = osd_yres; - else { - if (itv->is_50hz) - start_window.height = osd_compat ? max_height : 480; - else - start_window.height = osd_compat ? max_height : 400; - } + else + start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_upper --; + osd_upper--; start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - itv->osd_info->display_width = start_window.width; - itv->osd_info->display_height = start_window.height; + oi->display_width = start_window.width; + oi->display_height = start_window.height; /* Generate a valid fb_var_screeninfo */ - itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; - itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; - itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; - itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - itv->osd_info->ivtvfb_defined.nonstd = 0; + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; /* We've filled in the most data, let the usual mode check routine fill in the rest. */ - _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); /* Generate valid fb_fix_screeninfo */ - ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); /* Generate valid fb_info */ - itv->osd_info->ivtvfb_info.node = -1; - itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; - itv->osd_info->ivtvfb_info.par = itv; - itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; - itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; - itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; /* Supply some monitor specs. Bogus values will do for now */ - itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; - itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; - itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; - itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; /* Allocate color map */ - if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } /* Allocate the pseudo palette */ - itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - if (!itv->osd_info->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + if (!oi->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1038,51 +1001,53 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) static int ivtvfb_init_io(struct ivtv *itv) { - ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + struct osd_info *oi = itv->osd_info; + + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer size to prevent any overlap. */ - itv->osd_info->video_buffer_size = 1704960; + oi->video_buffer_size = 1704960; - itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; - itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; - if (!itv->osd_info->video_vbase) { + if (!oi->video_vbase) { IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + oi->video_buffer_size, oi->video_pbase); return -EIO; } IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - itv->osd_info->video_pbase, itv->osd_info->video_vbase, - itv->osd_info->video_buffer_size / 1024); + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); #ifdef CONFIG_MTRR { /* Find the largest power of two that maps the whole buffer */ int size_shift = 31; - while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + while (!(oi->video_buffer_size & (1 << size_shift))) { size_shift--; } size_shift++; - itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); - itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; - itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; - itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, - itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", - (unsigned int)itv->osd_info->fb_start_aligned_physaddr, - (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + IVTV_FB_WARN("cannot use mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; } } -#endif /* CONFIG_MTRR */ +#endif /* Blank the entire osd. */ - memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + memset_io(oi->video_vbase, 0, oi->video_buffer_size); return 0; } @@ -1090,26 +1055,30 @@ static int ivtvfb_init_io(struct ivtv *itv) /* Release any memory we've grabbed & remove mtrr entry */ static void ivtvfb_release_buffers (struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; + /* Release cmap */ - if (itv->osd_info->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ - if (itv->osd_info->ivtvfb_info.pseudo_palette) - kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); #ifdef CONFIG_MTRR - mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, - (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); -#endif /* CONFIG_MTRR */ + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif - kfree(itv->osd_info); + kfree(oi); itv->osd_info = NULL; } /* Initialize the specified card */ -static int ivtvfb_init_card (struct ivtv *itv) +static int ivtvfb_init_card(struct ivtv *itv) { int rc; @@ -1125,11 +1094,11 @@ static int ivtvfb_init_card (struct ivtv *itv) } /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io (itv))) + if ((rc = ivtvfb_init_io(itv))) return rc; /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode (itv))) { + if ((rc = ivtvfb_init_vidmode(itv))) { ivtvfb_release_buffers(itv); return rc; } From d715e766ddf4786a06abe6a841e956ad8a875963 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:30:32 -0300 Subject: [PATCH 010/310] V4L/DVB (5905): ivtv-fb: Use proper ioctl value Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 6 +++--- include/media/ivtv-fb.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 01cd65328e8a..55265bd5c250 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -424,10 +424,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar finish_wait(&itv->vsync_waitq, &wait); return rc; - case IVTVFB_IOCTL_PREP_FRAME: { - struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 902b2f3d3cb6..3b746f5e3c9e 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -23,13 +23,12 @@ /* Framebuffer external API */ -struct ivtvfb_ioctl_dma_host_to_ivtv_args { +struct ivtvfb_dma_frame { void __user *source; unsigned long dest_offset; int count; }; -/* Framebuffer ioctls should use the range 1 - 28 */ -#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #endif From 84149a0f70a73385ee7fbb77024544cbed4fe16d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 18:17:18 -0300 Subject: [PATCH 011/310] V4L/DVB (5906): ivtv-fb: replace HZ with msecs_to_jiffies Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 55265bd5c250..6f5da57299a1 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -420,7 +420,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; finish_wait(&itv->vsync_waitq, &wait); return rc; From aaf9fa21b684509973dd593e30423fc0a6a5e7a3 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sat, 21 Jul 2007 16:43:36 -0300 Subject: [PATCH 012/310] V4L/DVB (5908): ivtv-fb: cleanups, prevent fw calls in some cases Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 48 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 6f5da57299a1..56ce5c08bbb3 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -185,6 +185,9 @@ struct osd_info { unsigned long fb_end_aligned_physaddr; #endif + /* Current osd mode */ + int osd_mode; + /* Store the buffer offset */ int set_osd_coords_x; int set_osd_coords_y; @@ -350,6 +353,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; /* Nothing to do */ if (count == 0) { @@ -358,9 +362,9 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* Check Total FB Size */ - if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + if ((dest_offset + count) > oi->video_buffer_size) { IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, itv->osd_info->video_buffer_size); + dest_offset + count, oi->video_buffer_size); return -E2BIG; } @@ -387,7 +391,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); @@ -445,8 +449,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { + struct osd_info *oi = itv->osd_info; struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; + int osd_mode = -1; IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); @@ -456,32 +462,24 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) else /* RGB */ write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - /* Set the color mode - Although rare, occasionally things go wrong. The extra mode - change seems to help... */ - + /* Set the color mode */ switch (var->bits_per_pixel) { case 8: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + osd_mode = IVTV_OSD_BPP_8; break; case 32: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + osd_mode = IVTV_OSD_BPP_32; break; case 16: switch (var->green.length) { case 4: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + osd_mode = IVTV_OSD_BPP_16_444; break; case 5: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + osd_mode = IVTV_OSD_BPP_16_555; break; case 6: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + osd_mode = IVTV_OSD_BPP_16_565; break; default: IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); @@ -491,8 +489,17 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } - itv->osd_info->bits_per_pixel = var->bits_per_pixel; - itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + /* Change osd mode if needed. + Although rare, things can go wrong. The extra mode + change seems to help... */ + if (osd_mode != -1 && osd_mode != oi->osd_mode) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + oi->osd_mode = osd_mode; + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; /* Set the flicker filter */ switch (var->vmode & FB_VMODE_MASK) { @@ -887,6 +894,9 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->bits_per_pixel = osd_depth; oi->bytes_per_pixel = oi->bits_per_pixel / 8; + /* Invalidate current osd mode to force a mode switch later */ + oi->osd_mode = -1; + /* Horizontal size & position */ if (osd_xres > 720) osd_xres = 720; From f38a7982ad4c38dc592f7f0ac8ee155a2df19fb5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 08:39:43 -0300 Subject: [PATCH 013/310] V4L/DVB (5909): ivtv: update version to 1.1 to mark ivtv-fb support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 85530a3cd369..122d56105969 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -19,7 +19,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 0 +#define IVTV_DRIVER_VERSION_MINOR 1 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) From c6f95d16e0da4d909afc787a3a3dfc504be12177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 15:44:41 -0300 Subject: [PATCH 014/310] V4L/DVB (5910): ivtv-fb: improve debug message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 56ce5c08bbb3..b8ad249a0b17 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -439,7 +439,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); + IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; From 915366da0c591f60cb670d89b5ff376f2ef9d8fe Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:33:26 -0300 Subject: [PATCH 015/310] V4L/DVB (5912): Clean up duplicate includes in drivers/media/ This patch cleans up duplicate includes in drivers/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 649f52f9ad27..2666d3b76630 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index da7a6b591a67..c34158d9dcc1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "cx88.h" diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 06b233a7b20b..41b5cb63fd2d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "cx88.h" From 59a00adbd30ed5d3a97ac41ad9e4b040a111eea8 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:34:34 -0300 Subject: [PATCH 016/310] V4L/DVB (5913): Clean up duplicate includes in include/media/ This patch cleans up duplicate includes in include/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-dev.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 17f8f3a2f0a3..8b79e2cf77fa 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -23,8 +23,6 @@ #include #endif -#include - #define VIDEO_MAJOR 81 /* Minor device allocation */ #define MINOR_VFL_TYPE_GRABBER_MIN 0 From 54d75ebaa02809f24a16624e32706af3bf97588e Mon Sep 17 00:00:00 2001 From: Olivier DANET Date: Wed, 25 Jul 2007 14:42:54 -0300 Subject: [PATCH 017/310] V4L/DVB (5914): Add initial support for Dual-DVB-T stick Add initial support for Dual-DVB-T stick based on DiB7700 and MT2266 - Microtune MT2266 driver. - Preliminary support for these dual tuner devices : - Pinnacle Dual DVB-T diversity - Terratec Cinergy DT USB XS diversity - Hauppauge Nova TD USB Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700.h | 4 +- drivers/media/dvb/dvb-usb/dib0700_core.c | 2 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 262 ++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 5 +- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib7000p.c | 5 + drivers/media/dvb/frontends/dib7000p.h | 2 +- drivers/media/dvb/frontends/mt2266.c | 288 ++++++++++++++++++++ drivers/media/dvb/frontends/mt2266.h | 37 +++ 11 files changed, 609 insertions(+), 5 deletions(-) create mode 100644 drivers/media/dvb/frontends/mt2266.c create mode 100644 drivers/media/dvb/frontends/mt2266.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 40e41f2f5afe..dec03ee32e1a 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -74,6 +74,7 @@ config DVB_USB_DIB0700 select DVB_DIB7000M select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index cda3adea24fb..74ae6c24087e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -35,12 +35,13 @@ extern int dvb_usb_dib0700_debug; struct dib0700_state { u8 channel_state; u16 mt2060_if1[2]; - + u8 rc_toggle; u8 is_dib7000pc; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; @@ -50,5 +51,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device extern int dib0700_device_count; extern struct dvb_usb_device_properties dib0700_devices[]; extern struct usb_device_id dib0700_usb_id_table[]; - #endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index dddf164f269a..8a1ea114deb0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -32,7 +32,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) } /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) { u16 index, value; int status; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2208757d9017..122d9d4b4baa 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -12,6 +12,7 @@ #include "dib7000m.h" #include "dib7000p.h" #include "mt2060.h" +#include "mt2266.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); @@ -96,6 +97,228 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } +/* STK7700D: Pinnacle Dual DVB-T Diversity */ + +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { + BAND_UHF/* | BAND_VHF*/, + 0xE64, // setup + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 0, // wbd_ref + 0, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit : 1 en vrai! +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, // internal, sampling + 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + 0, // ifreq + 20452225, // timf +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;; +} + +#define DEFAULT_RC_INTERVAL 150 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[4]; + int i; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + i=dib0700_ctrl_rd(d,rc_request,2,key,4); + if (i<=0) { + err("stk7700d:RC Query Failed\n"); + return 0; + } + if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; + if (key[1]!=st->rc_toggle) { + for (i=0;iprops.rc_key_map_size; i++) { + if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + st->rc_toggle=key[1]; + return 0; + } + } + err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + } + return 0; +} + +#define KEY_MAP_SIZE (25+48) + +struct dvb_usb_rc_key stk7700d_rc_keys[] = { + /* Key codes for the tiny Pinnacle remote*/ + { 0x07, 0x00, KEY_MUTE }, + { 0x07, 0x01, KEY_MENU }, // Pinnacle logo + { 0x07, 0x39, KEY_POWER }, + { 0x07, 0x03, KEY_VOLUMEUP }, + { 0x07, 0x09, KEY_VOLUMEDOWN }, + { 0x07, 0x06, KEY_CHANNELUP }, + { 0x07, 0x0c, KEY_CHANNELDOWN }, + { 0x07, 0x0f, KEY_1 }, + { 0x07, 0x15, KEY_2 }, + { 0x07, 0x10, KEY_3 }, + { 0x07, 0x18, KEY_4 }, + { 0x07, 0x1b, KEY_5 }, + { 0x07, 0x1e, KEY_6 }, + { 0x07, 0x11, KEY_7 }, + { 0x07, 0x21, KEY_8 }, + { 0x07, 0x12, KEY_9 }, + { 0x07, 0x27, KEY_0 }, + { 0x07, 0x24, KEY_SCREEN }, // 'Square' key + { 0x07, 0x2a, KEY_TEXT }, // 'T' key + { 0x07, 0x2d, KEY_REWIND }, + { 0x07, 0x30, KEY_PLAY }, + { 0x07, 0x33, KEY_FASTFORWARD }, + { 0x07, 0x36, KEY_RECORD }, + { 0x07, 0x3c, KEY_STOP }, + { 0x07, 0x3f, KEY_CANCEL }, // '?' key + /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ + { 0xeb, 0x01, KEY_POWER }, + { 0xeb, 0x02, KEY_1 }, + { 0xeb, 0x03, KEY_2 }, + { 0xeb, 0x04, KEY_3 }, + { 0xeb, 0x05, KEY_4 }, + { 0xeb, 0x06, KEY_5 }, + { 0xeb, 0x07, KEY_6 }, + { 0xeb, 0x08, KEY_7 }, + { 0xeb, 0x09, KEY_8 }, + { 0xeb, 0x0a, KEY_9 }, + { 0xeb, 0x0b, KEY_VIDEO }, + { 0xeb, 0x0c, KEY_0 }, + { 0xeb, 0x0d, KEY_REFRESH }, + { 0xeb, 0x0f, KEY_EPG }, + { 0xeb, 0x10, KEY_UP }, + { 0xeb, 0x11, KEY_LEFT }, + { 0xeb, 0x12, KEY_OK }, + { 0xeb, 0x13, KEY_RIGHT }, + { 0xeb, 0x14, KEY_DOWN }, + { 0xeb, 0x16, KEY_INFO }, + { 0xeb, 0x17, KEY_RED }, + { 0xeb, 0x18, KEY_GREEN }, + { 0xeb, 0x19, KEY_YELLOW }, + { 0xeb, 0x1a, KEY_BLUE }, + { 0xeb, 0x1b, KEY_CHANNELUP }, + { 0xeb, 0x1c, KEY_VOLUMEUP }, + { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1e, KEY_VOLUMEDOWN }, + { 0xeb, 0x1f, KEY_CHANNELDOWN }, + { 0xeb, 0x40, KEY_PAUSE }, + { 0xeb, 0x41, KEY_HOME }, + { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */ + { 0xeb, 0x43, KEY_SUBTITLE }, + { 0xeb, 0x44, KEY_TEXT }, /* Teletext */ + { 0xeb, 0x45, KEY_DELETE }, + { 0xeb, 0x46, KEY_TV }, + { 0xeb, 0x47, KEY_DVD }, + { 0xeb, 0x48, KEY_STOP }, + { 0xeb, 0x49, KEY_VIDEO }, + { 0xeb, 0x4a, KEY_AUDIO }, /* Music */ + { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */ + { 0xeb, 0x4c, KEY_PLAY }, + { 0xeb, 0x4d, KEY_BACK }, + { 0xeb, 0x4e, KEY_REWIND }, + { 0xeb, 0x4f, KEY_FASTFORWARD }, + { 0xeb, 0x54, KEY_PREVIOUS }, + { 0xeb, 0x58, KEY_RECORD }, + { 0xeb, 0x5c, KEY_NEXT } + }; + /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { BAND_UHF | BAND_VHF, // band_caps @@ -280,6 +503,9 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -372,6 +598,42 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 3, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Haupauge Nova-TD Stick", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + }, + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = stk7700d_rc_keys, + .rc_key_map_size = KEY_MAP_SIZE, + .rc_query = stk7700d_rc_query } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 78ea3b566ffc..2e38be3aa45b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_AFATECH 0x15a4 -#define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd @@ -116,8 +116,11 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ff448761dcef..ba70ad0c3f05 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -322,6 +322,13 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config DVB_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 156b062e02c4..217265ca2849 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aece458cfe12..c24189fcbc89 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -112,6 +112,11 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) break; } + if (state->cfg.hostbus_diversity) { + ret |= dib7000p_write_word(state, 204, 1); // Diversity ? + ret |= dib7000p_write_word(state, 205, 0); // Diversity ? + } + if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 79465cf1aced..94829c1ed054 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -35,7 +35,7 @@ struct dib7000p_config { extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c new file mode 100644 index 000000000000..145135778bce --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.c @@ -0,0 +1,288 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { + REG_TUNE, + 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, + 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + +static u8 mt2266_init_8mhz[] = { + REG_BANDWIDTH, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { + REG_BANDWIDTH, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { + REG_BANDWIDTH, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + + priv = fe->tuner_priv; + + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + + freq = params->frequency / 1000; // Hz -> kHz + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq * 1000; + tune=2 * freq * (8192/16) / (FREF/16); + + if (freq <= 495000) lnaband = 0xEE; else + if (freq <= 525000) lnaband = 0xDD; else + if (freq <= 550000) lnaband = 0xCC; else + if (freq <= 580000) lnaband = 0xBB; else + if (freq <= 605000) lnaband = 0xAA; else + if (freq <= 630000) lnaband = 0x99; else + if (freq <= 655000) lnaband = 0x88; else + if (freq <= 685000) lnaband = 0x77; else + if (freq <= 710000) lnaband = 0x66; else + if (freq <= 735000) lnaband = 0x55; else + if (freq <= 765000) lnaband = 0x44; else + if (freq <= 802000) lnaband = 0x33; else + if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; + + msleep(100); + mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: + (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: + mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); + + b[0] = 0x05; + b[1] = 0x62; + b[2] = lnaband; + mt2266_writeregs(priv,b,3); + + //Waits for pll lock or timeout + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if ((b[0] & 0x40)==0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i\n",(int)i); + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv,0x11,0x03); + mt2266_writereg(priv,0x11,0x01); + + mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); + mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); + + mt2266_writereg(priv,0x33,0x5e); + mt2266_writereg(priv,0x10,0x10); + mt2266_writereg(priv,0x10,0x00); + + mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + msleep(25); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + msleep(75); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (mt2266_readreg(priv,0,&id) != 0) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h new file mode 100644 index 000000000000..f31dd613ad37 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.h @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2266 + +#endif From 7bb293849489b6cc5d6919b8c7f94cb273303e1f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 09:42:09 -0300 Subject: [PATCH 018/310] V4L/DVB (5919): ivtv: remove dead code Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 51df3f855031..405e2e3fcb49 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -314,15 +314,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) int lines; int i; - /* If Embed then streamtype must be Program */ - /* TODO: should we really do this? */ - if (0 && !raw && itv->vbi.insert_mpeg) { - itv->params.stream_type = 0; - - /* assign stream type */ - ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); - } - /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); From fa8a7529ba8c3c2f87dec78ad32c388695f4c1b7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:13:08 -0300 Subject: [PATCH 019/310] V4L/DVB (5921): ivtv: add missing composite input line for ivtv_pci_pg600v2 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 8eab02083887..baab14b40e87 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -845,6 +845,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, From c976bc82339437e840f7dbf0b8c89c09d3fcd75e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:52:40 -0300 Subject: [PATCH 020/310] V4L/DVB (5922): ivtv, cx25840: postpone fw load until first use The firmware is now loaded when the driver is actually used for the first time. This allows the driver to be compiled in-kernel instead of as a module. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/cx25840/cx25840-core.c | 21 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + drivers/media/video/ivtv/ivtv-driver.c | 189 ++++++++++----------- drivers/media/video/ivtv/ivtv-driver.h | 5 + drivers/media/video/ivtv/ivtv-fileops.c | 9 + 6 files changed, 127 insertions(+), 101 deletions(-) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8f7205b558f6..c5286bfba447 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o @@ -117,6 +116,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ +obj-$(CONFIG_VIDEO_IVTV) += ivtv/ + obj-$(CONFIG_VIDEO_VIVI) += vivi.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 67bda9f9a44b..9c12bd39cfb5 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -625,6 +625,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, struct v4l2_tuner *vt = arg; struct v4l2_routing *route = arg; + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + if (state->is_cx25836) + cx25836_initialize(client); + else + cx25840_initialize(client, 1); + } + switch (cmd) { #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the @@ -906,11 +922,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_attach_client(client); - if (state->is_cx25836) - cx25836_initialize(client); - else - cx25840_initialize(client, 1); - return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index f4b56d2fd6b6..8c1fbd9b87c1 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -46,6 +46,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_initialized; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 81cbaf7dd51c..00bdcc2e8f53 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -814,7 +814,6 @@ static void ivtv_request_module(struct ivtv *itv, const char *name) static void ivtv_load_and_init_modules(struct ivtv *itv) { - struct v4l2_control ctrl; u32 hw = itv->card->hw_all; int i; @@ -896,11 +895,6 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) } if (hw & IVTV_HW_CX25840) { - /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ - ctrl.id = V4L2_CID_PRIVATE_BASE; - ctrl.value = itv->pvr150_workaround; - itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); - itv->vbi.raw_decoder_line_size = 1444; itv->vbi.raw_decoder_sav_odd_field = 0x20; itv->vbi.raw_decoder_sav_even_field = 0x60; @@ -946,12 +940,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int video_input; int yuv_buf_size; int vbi_buf_size; - int fw_retry_count = 3; struct ivtv *itv; - struct v4l2_frequency vf; spin_lock(&ivtv_cards_lock); @@ -1038,22 +1029,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, goto free_io; } - while (--fw_retry_count > 0) { - /* load firmware */ - if (ivtv_firmware_init(itv) == 0) - break; - if (fw_retry_count > 1) - IVTV_WARN("Retry loading firmware\n"); - } - if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - goto free_i2c; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - /* Check yuv output filter table */ if (itv->has_cx23415) ivtv_yuv_filter_check(itv); @@ -1157,44 +1132,16 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (itv->std == V4L2_STD_NTSC_M_JP) { - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - } - else if (itv->std & V4L2_STD_NTSC_M) { - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - } - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ itv->tuner_std = itv->std; - video_input = itv->active_input; - itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - itv->std++; /* Force full standard initialization */ - itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); - retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); goto free_i2c; } - if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_init_mpeg_decoder(itv); - } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1206,26 +1153,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } - - /* On a cx23416 this seems to be able to enable DMA to the chip? */ - if (!itv->has_cx23415) - write_reg_sync(0x03, IVTV_REG_DMACONTROL); - - /* Default interrupts enabled. For the PVR350 this includes the - decoder VSYNC interrupt, which is always on. It is not only used - during decoding but also by the OSD. - Some old PVR250 cards had a cx23415, so testing for that is too - general. Instead test if the card has video output capability. */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - if (itv->has_cx23415) - ivtv_set_osd_alpha(itv); - IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); - return 0; free_irq: @@ -1255,55 +1183,126 @@ static int __devinit ivtv_probe(struct pci_dev *dev, return retval; } +int ivtv_init_on_first_open(struct ivtv *itv) +{ + struct v4l2_frequency vf; + int fw_retry_count = 3; + int video_input; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (ivtv_firmware_init(itv) == 0) + break; + if (fw_retry_count > 1) + IVTV_WARN("Retry loading firmware\n"); + } + if (fw_retry_count == 0) { + IVTV_ERR("Error initializing firmware\n"); + return -1; + } + + /* Try and get firmware versions */ + IVTV_DEBUG_INFO("Getting firmware version..\n"); + ivtv_firmware_versions(itv); + + if (itv->card->hw_all & IVTV_HW_CX25840) { + struct v4l2_control ctrl; + + /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ + ctrl.id = V4L2_CID_PRIVATE_BASE; + ctrl.value = itv->pvr150_workaround; + itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + } + + video_input = itv->active_input; + itv->active_input++; /* Force update of input */ + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + itv->std++; /* Force full standard initialization */ + itv->std_out = itv->std; + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); + + if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_init_mpeg_decoder(itv); + } + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); + + /* On a cx23416 this seems to be able to enable DMA to the chip? */ + if (!itv->has_cx23415) + write_reg_sync(0x03, IVTV_REG_DMACONTROL); + + /* Default interrupts enabled. For the PVR350 this includes the + decoder VSYNC interrupt, which is always on. It is not only used + during decoding but also by the OSD. + Some old PVR250 cards had a cx23415, so testing for that is too + general. Instead test if the card has video output capability. */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); + ivtv_set_osd_alpha(itv); + } + else + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); + return 0; +} + static void ivtv_remove(struct pci_dev *pci_dev) { struct ivtv *itv = pci_get_drvdata(pci_dev); IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num); - /* Stop all captures */ - IVTV_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&itv->capturing) > 0) - ivtv_stop_all_captures(itv); + if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { + /* Stop all captures */ + IVTV_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&itv->capturing) > 0) + ivtv_stop_all_captures(itv); - /* Stop all decoding */ - IVTV_DEBUG_INFO("Stopping decoding\n"); - if (atomic_read(&itv->decoding) > 0) { - int type; + /* Stop all decoding */ + IVTV_DEBUG_INFO("Stopping decoding\n"); + if (atomic_read(&itv->decoding) > 0) { + int type; - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - type = IVTV_DEC_STREAM_TYPE_YUV; - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], - VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + type = IVTV_DEC_STREAM_TYPE_YUV; + else + type = IVTV_DEC_STREAM_TYPE_MPG; + ivtv_stop_v4l2_decode_stream(&itv->streams[type], + VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + } + ivtv_halt_firmware(itv); } /* Interrupts */ - IVTV_DEBUG_INFO("Disabling interrupts\n"); ivtv_set_irq_mask(itv, 0xffffffff); del_timer_sync(&itv->dma_timer); /* Stop all Work Queues */ - IVTV_DEBUG_INFO("Stop Work Queues\n"); flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); - IVTV_DEBUG_INFO("Stopping Firmware\n"); - ivtv_halt_firmware(itv); - - IVTV_DEBUG_INFO("Unregistering v4l devices\n"); ivtv_streams_cleanup(itv); - IVTV_DEBUG_INFO("Freeing dma resources\n"); ivtv_udma_free(itv); exit_ivtv_i2c(itv); - IVTV_DEBUG_INFO(" Releasing irq\n"); free_irq(itv->dev->irq, (void *)itv); ivtv_iounmap(itv); - IVTV_DEBUG_INFO(" Releasing mem\n"); release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8fe9d9c7a18e..6e53a1f04f7e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -398,6 +398,8 @@ struct ivtv_mailbox_data { #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ #define IVTV_F_I_PIO 19 /* PIO in progress */ #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ +#define IVTV_F_I_INITED 21 /* set after first open */ +#define IVTV_F_I_FAILED 22 /* set if first open failed */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ @@ -838,6 +840,9 @@ int ivtv_waitq(wait_queue_head_t *waitq); struct tveeprom; /* forward reference */ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); +/* First-open initialization: load firmware, init cx25840, etc. */ +int ivtv_init_on_first_open(struct ivtv *itv); + /* This is a PCI post thing, where if the pci register is not read, then the write doesn't always take effect right away. By reading back the register any pending PCI writes will be performed (in order), and so diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 66ea3cbc369c..498860841644 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -850,6 +850,15 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENXIO; } + if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + if (ivtv_init_on_first_open(itv)) + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { + printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + return -ENXIO; + } + if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; From 6e5eb59102aa6007d3ea2b382a1d3ca4112c272a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 25 Jul 2007 12:55:52 -0300 Subject: [PATCH 021/310] V4L/DVB (5924): ivtv-fb: initializing the fb should trigger ivtv firmware load ivtv-fb: initializing the framebuffer should trigger ivtv firmware load Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 12 ++++++++++-- drivers/media/video/ivtv/ivtv-fb.c | 5 +++++ drivers/media/video/ivtv/ivtv-fileops.c | 10 +++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 00bdcc2e8f53..55ed0305fd64 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1189,6 +1189,12 @@ int ivtv_init_on_first_open(struct ivtv *itv) int fw_retry_count = 3; int video_input; + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) + return -ENXIO; + + if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + return 0; + while (--fw_retry_count > 0) { /* load firmware */ if (ivtv_firmware_init(itv) == 0) @@ -1196,9 +1202,10 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (fw_retry_count > 1) IVTV_WARN("Retry loading firmware\n"); } + if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - return -1; + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + return -ENXIO; } /* Try and get firmware versions */ @@ -1381,6 +1388,7 @@ EXPORT_SYMBOL(ivtv_udma_setup); EXPORT_SYMBOL(ivtv_udma_unmap); EXPORT_SYMBOL(ivtv_udma_alloc); EXPORT_SYMBOL(ivtv_udma_prepare); +EXPORT_SYMBOL(ivtv_init_on_first_open); module_init(module_start); module_exit(module_cleanup); diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index b8ad249a0b17..00765da8a6a0 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1013,6 +1013,11 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + if (ivtv_init_on_first_open(itv)) { + IVTV_FB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 498860841644..fedddecf661e 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -846,16 +846,12 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) if (itv == NULL) { /* Couldn't find a device registered on that minor, shouldn't happen! */ - printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor); + IVTV_WARN("No ivtv device found on minor %d\n", minor); return -ENXIO; } - if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) - if (ivtv_init_on_first_open(itv)) - set_bit(IVTV_F_I_FAILED, &itv->i_flags); - - if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { - printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } From 469ba047c08669f364c2616967e8494b1f3ef21c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:51:58 -0300 Subject: [PATCH 022/310] V4L/DVB (5927): ivtv: set correct crystal frequency of the GVMVPRX cards Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 55ed0305fd64..cf52111a2dcc 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -57,6 +57,7 @@ #include "ivtv-yuv.h" #include +#include #include /* var to keep track of the number of array elements in use */ @@ -893,6 +894,15 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) else if ((hw & IVTV_HW_UPD64031A) == 0) itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); } + else if (itv->card->type == IVTV_CARD_GV_MVPRX || + itv->card->type == IVTV_CARD_GV_MVPRX2E) { + struct v4l2_crystal_freq crystal_freq; + + /* The crystal frequency of GVMVPRX is 24.576MHz */ + crystal_freq.freq = SAA7115_FREQ_24_576_MHZ; + crystal_freq.flags = SAA7115_FREQ_FL_UCGC; + itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq); + } if (hw & IVTV_HW_CX25840) { itv->vbi.raw_decoder_line_size = 1444; From b4c85248afcc5265ce8c36b9c15e40e6a92b5ae7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:53:23 -0300 Subject: [PATCH 023/310] V4L/DVB (5928): tuner: fix TOP values for the Panasonic VP27 tuner. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 417f642b4359..53a99b39387f 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -670,6 +670,9 @@ static struct tuner_params tuner_panasonic_vp27_params[] = { .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), .has_tda9887 = 1, .intercarrier_mode = 1, + .default_top_low = -3, + .default_top_mid = -3, + .default_top_high = -3, }, }; From ac247433fe205acf460f05de64a30ee71ea307f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 27 Jul 2007 06:56:50 -0300 Subject: [PATCH 024/310] V4L/DVB (5929): Add vp27smpx driver This device is internal to the Panasonic VP27S tuner and is used to set the mono/stereo/bilingual setting of the tuner. It is used by two Japanese cx23416-based cards. Signed-off-by: Takahiro Adachi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 ++ drivers/media/video/Makefile | 1 + drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 4 +- drivers/media/video/ivtv/ivtv-cards.h | 3 +- drivers/media/video/ivtv/ivtv-driver.c | 4 + drivers/media/video/ivtv/ivtv-i2c.c | 2 + drivers/media/video/vp27smpx.c | 211 +++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + include/media/v4l2-chip-ident.h | 3 + 10 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 drivers/media/video/vp27smpx.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 675c8574403e..0e1d2ccc4e81 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -148,6 +148,15 @@ config VIDEO_WM8739 To compile this driver as a module, choose M here: the module will be called wm8739. +config VIDEO_VP27SMPX + tristate "Panasonic VP27s internal MPX" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the internal MPX of the Panasonic VP27s tuner. + + To compile this driver as a module, choose M here: the + module will be called vp27smpx. + comment "Video decoders" config VIDEO_BT819 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c5286bfba447..113e525f6dab 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 399f231abb96..5efacb332114 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -14,6 +14,7 @@ config VIDEO_IVTV select VIDEO_CS53L32A select VIDEO_WM8775 select VIDEO_WM8739 + select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 ---help--- diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index baab14b40e87..e51d7cc35b1c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | IVTV_HW_TUNER | IVTV_HW_WM8739 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .video_inputs = { @@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_TVAUDIO | IVTV_HW_WM8739, + IVTV_HW_VP27SMPX | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 91e9e90c14a5..3191920f4c6b 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -33,7 +33,8 @@ #define IVTV_HW_UPD6408X (1 << 11) #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_GPIO (1 << 14) +#define IVTV_HW_VP27SMPX (1 << 14) +#define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index cf52111a2dcc..f8ef267e56b2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -853,6 +853,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifndef CONFIG_VIDEO_MSP3400 if (hw & IVTV_HW_MSP34XX) ivtv_request_module(itv, "msp3400"); +#endif +#ifndef CONFIG_VIDEO_VP27SMPX + if (hw & IVTV_HW_VP27SMPX) + ivtv_request_module(itv, "vp27smpx"); #endif if (hw & IVTV_HW_TVAUDIO) ivtv_request_module(itv, "tvaudio"); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index b3557435456d..5e12ebc2a9de 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -109,6 +109,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, + I2C_DRIVERID_VP27SMPX, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = { "upd64083", "saa717x", "wm8739", + "vp27smpx", "gpio", }; diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c new file mode 100644 index 000000000000..9aa526bd2c84 --- /dev/null +++ b/drivers/media/video/vp27smpx.c @@ -0,0 +1,211 @@ +/* + * vp27smpx - driver version 0.0.1 + * + * Copyright (C) 2007 Hans Verkuil + * + * Special thanks to Kazz for the i2c data. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("vp27smpx driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +/* ----------------------------------------------------------------------- */ + +struct vp27smpx_state { + int radio; + u32 audmode; +}; + +static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + u8 data[3] = { 0x00, 0x00, 0x04 }; + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; + } + + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { + v4l_err(client, "%s: I/O error setting audmode\n", client->name); + } + else { + state->audmode = audmode; + } +} + +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + struct v4l2_tuner *vt = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_S_STD: + state->radio = 0; + break; + + case VIDIOC_S_TUNER: + if (!state->radio) + vp27smpx_set_audmode(client, vt->audmode); + break; + + case VIDIOC_G_TUNER: + if (state->radio) + break; + vt->audmode = state->audmode; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Audio Mode: %u%s\n", state->audmode, + state->radio ? " (Radio)" : ""); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static struct i2c_driver i2c_driver; + +static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct vp27smpx_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->audmode = V4L2_TUNER_MODE_STEREO; + i2c_set_clientdata(client, state); + + /* initialize vp27smpx */ + vp27smpx_set_audmode(client, state->audmode); + i2c_attach_client(client); + + return 0; +} + +static int vp27smpx_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, vp27smpx_attach); + return 0; +} + +static int vp27smpx_detach(struct i2c_client *client) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "vp27smpx", + }, + .id = I2C_DRIVERID_VP27SMPX, + .attach_adapter = vp27smpx_probe, + .detach_client = vp27smpx_detach, + .command = vp27smpx_command, +}; + + +static int __init vp27smpx_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit vp27smpx_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(vp27smpx_init_module); +module_exit(vp27smpx_cleanup_module); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b69014865714..4891e03ad23a 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -119,6 +119,7 @@ #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ +#define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 09d16c4f00f7..8ae42c41dd08 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -65,6 +65,9 @@ enum { V4L2_IDENT_CX23415 = 415, V4L2_IDENT_CX23416 = 416, + /* module vp27smpx: just ident 2700 */ + V4L2_IDENT_VP27SMPX = 2700, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, From 36c15f8ee41fbc3d8eaf88bba95be3d50268d5d2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 13:59:55 -0300 Subject: [PATCH 025/310] V4L/DVB (5934): dvb-ttpci/saa7146: Replace saa7146_i2c_transfer by generic i2c_transfer Convert av7110_v4l.c to use i2c_transfer() instead of saa7146_i2c_transfer(). Make saa7146_i2c_transfer() static. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 1 - drivers/media/common/saa7146_i2c.c | 2 +- drivers/media/dvb/ttpci/av7110_v4l.c | 6 ++++-- include/media/saa7146.h | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index ba6701e97671..12cda9eebd12 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -548,7 +548,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); EXPORT_SYMBOL_GPL(saa7146_setgpio); -EXPORT_SYMBOL_GPL(saa7146_i2c_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug); diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 8c85efc26527..f823286341eb 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -277,7 +277,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) +static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 87afaebc0703..76cca003252f 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = { static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) { + struct av7110 *av7110 = dev->ext_priv; u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) { + struct av7110 *av7110 = dev->ext_priv; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 67703249b245..cd3ff2c29d5e 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -146,7 +146,6 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; From 1fab46f0decd226fcbae73b23d7f8ed478416fbb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:00:36 -0300 Subject: [PATCH 026/310] V4L/DVB (5935): dvb_frontend: Range check of frequency and symbol rate Add range check of frequency and symbol rate to the FE_SET_FRONTEND ioctl. This will also avoid a divide-by zero exception in the stv0297 driver, if symbol rate is set to 0. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index b6c7f6610ec5..384b5b8959c1 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,6 +697,47 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static int dvb_frontend_check_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *parms) +{ + /* range check: frequency */ + if ((fe->ops.info.frequency_min && + parms->frequency < fe->ops.info.frequency_min) || + (fe->ops.info.frequency_max && + parms->frequency > fe->ops.info.frequency_max)) { + printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", + fe->dvb->num, parms->frequency, + fe->ops.info.frequency_min, fe->ops.info.frequency_max); + return -EINVAL; + } + + /* range check: symbol rate */ + if (fe->ops.info.type == FE_QPSK) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qpsk.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + + } else if (fe->ops.info.type == FE_QAM) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qam.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + } + + return 0; +} + static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { @@ -883,6 +924,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } + memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); From 92b3c1ec128695e606fc435d0b68902105d585bb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:14:10 -0300 Subject: [PATCH 027/310] V4L/DVB (5936): tda10023: Remove range check of symbol rate Remove incorrect range check of symbol rate, spotted by the coverity checker and reported by Adrian Bunk. These range checks are performed by dvb_core now. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda10023.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index 4bb06f97938b..a00cf0f54efc 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) s16 SFIL=0; u16 NDEC = 0; - if (sr > (SYSCLK/(2*4))) - sr=SYSCLK/(2*4); - - if (sr<870000) - sr=870000; - if (sr < (u32)(SYSCLK/98.40)) { NDEC=3; SFIL=1; From 261efd12fc291e6b3b42011201bfd011484ad90b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 30 Jul 2007 11:43:55 -0300 Subject: [PATCH 028/310] V4L/DVB (5940): Export v4l2_int_device_{, un}register This patch fixes the following build error: <-- snip --> ... MODPOST 2135 modules make[2]: *** [__modpost] Error 1 <-- snip --> Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index aa2a8156338d..a643730fa3b2 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -101,6 +101,7 @@ int v4l2_int_device_register(struct v4l2_int_device *d) return 0; } +EXPORT_SYMBOL_GPL(v4l2_int_device_register); void v4l2_int_device_unregister(struct v4l2_int_device *d) { @@ -114,6 +115,7 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) } mutex_unlock(&mutex); } +EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); /* Adapted from search_extable in extable.c. */ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, From af520a3478b59476ed61eddee73948807398e358 Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:48:10 -0300 Subject: [PATCH 029/310] V4L/DVB (5941): Ttpci/budget-av.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 0aee7a13a070..3439c9864f67 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 .flags = 0, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .ioctls = &ioctls[0], .ioctl = av_ioctl, }; From 667c7bc0aff18288186f1223784b57f77be7d81b Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:49:51 -0300 Subject: [PATCH 030/310] V4L/DVB (5942): Usb/vp7045.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/vp7045.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 69a46b3607a2..5bbd2d5192f0 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; *event = vp7045_rc_keys[i].event; From 03b7612336560c6799852acaaaeac70e1f00e483 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 30 Jul 2007 14:58:10 -0300 Subject: [PATCH 031/310] V4L/DVB (5946): Use mutex instead of semaphore in the DVB frontend tuning interface The DVB frontend tuning interface uses a semaphore as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 10 +++++----- drivers/media/dvb/dvb-core/dvb_frontend.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 384b5b8959c1..afe797b75de4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -138,7 +138,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __FUNCTION__); - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return; wp = (events->eventw + 1) % MAX_EVENT; @@ -159,7 +159,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) events->eventw = wp; - up (&events->sem); + mutex_unlock(&events->mtx); e->status = status; @@ -197,7 +197,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return ret; } - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return -ERESTARTSYS; memcpy (event, &events->events[events->eventr], @@ -205,7 +205,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, events->eventr = (events->eventr + 1) % MAX_EVENT; - up (&events->sem); + mutex_unlock(&events->mtx); return 0; } @@ -1126,7 +1126,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->sem); init_waitqueue_head (&fepriv->wait_queue); init_waitqueue_head (&fepriv->events.wait_queue); - init_MUTEX (&fepriv->events.sem); + mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a770a87b9a93..f95de63d0e24 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -142,7 +143,7 @@ struct dvb_fe_events { int eventr; int overflow; wait_queue_head_t wait_queue; - struct semaphore sem; + struct mutex mtx; }; struct dvb_frontend { From f47623a04dab402fb2c18fe516a174bc02005629 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:17:39 -0300 Subject: [PATCH 032/310] V4L/DVB (5947): Adding support for the MT2131 tuner. This adds support for the Microtune MT2131 tuner. 8VSB mode has been tested but QAM support will likely require more register work. Hauppauge have not announced any QAM devices using the MT2131 so QAM remains undone. For legal reasons, Microtune allowed us to write a GPL driver providing we did not document in significant detail any of the registers. This explains the lack of comments or defined on register names. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/mt2131.c | 308 ++++++++++++++++++++++ drivers/media/dvb/frontends/mt2131.h | 49 ++++ drivers/media/dvb/frontends/mt2131_priv.h | 44 ++++ 5 files changed, 409 insertions(+) create mode 100644 drivers/media/dvb/frontends/mt2131.c create mode 100644 drivers/media/dvb/frontends/mt2131.h create mode 100644 drivers/media/dvb/frontends/mt2131_priv.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ba70ad0c3f05..c3c8af771f80 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -329,6 +329,13 @@ config DVB_TUNER_MT2266 help A driver for the silicon baseband tuner MT2266 from Microtune. +config DVB_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 217265ca2849..a8cfa03b273c 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c new file mode 100644 index 000000000000..4fe1e62c9f06 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.c @@ -0,0 +1,308 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 v; + + mt2131_readreg(priv, 0x07, &v); + mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); + + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1,f_lo2; + u32 div1,num1,div2,num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + if (fe->ops.info.type == FE_OFDM) + priv->bandwidth = params->u.ofdm.bandwidth; + else + priv->bandwidth = 0; + + freq = params->frequency / 1000; // Hz -> kHz + dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000, + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __FUNCTION__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_bandwidth = mt2131_get_bandwidth, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h new file mode 100644 index 000000000000..5d1f281d87b2 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.h @@ -0,0 +1,49 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2131 + +#endif // __MT2131_H__ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h new file mode 100644 index 000000000000..fe6333b49c93 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -0,0 +1,44 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef MT2131_PRIV_H +#define MT2131_PRIV_H + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +#endif From 89885558ada9e076b48f4b6887e252e13e7eaf74 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:34:52 -0300 Subject: [PATCH 033/310] V4L/DVB (5948): Adding support for the S5H1409/CX24227 8VSB/QAM demodulator. This patch adds support for the Samsung S5H1409 demodulator, also known as the Conexant CX24227 demodulator. 8VSB mode has been tested and QAM has been implemented based on the spec, although it's untested. The S5H1409 / CX24227 appears on various Hauppauge boards. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 8 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/s5h1409.c | 715 ++++++++++++++++++++++++++ drivers/media/dvb/frontends/s5h1409.h | 68 +++ 4 files changed, 792 insertions(+) create mode 100644 drivers/media/dvb/frontends/s5h1409.c create mode 100644 drivers/media/dvb/frontends/s5h1409.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index c3c8af771f80..faf9fe3c9cce 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -283,6 +283,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_S5H1409 + tristate "Samsung S5H1409 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + comment "Tuners/PLL support" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a8cfa03b273c..c46b9d8e9313 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_DVB_S5H1409) += s5h1409.o diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c new file mode 100644 index 000000000000..4b77390f5d4b --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -0,0 +1,715 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "s5h1409.h" + +struct s5h1409_state { + + struct i2c_adapter* i2c; + + /* configuration settings */ + const struct s5h1409_config* config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_modulation_t current_modulation; + + u32 current_frequency; +}; + +static int debug = 0; +#define dprintk if (debug) printk + +/* Register values to initialise the demod, this will set VSB by default */ +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { 0x00, 0x0071, }, + { 0x01, 0x3213, }, + { 0x09, 0x0025, }, + { 0x1c, 0x001d, }, + { 0x1f, 0x002d, }, + { 0x20, 0x001d, }, + { 0x22, 0x0022, }, + { 0x23, 0x0020, }, + { 0x29, 0x110f, }, + { 0x2a, 0x10b4, }, + { 0x2b, 0x10ae, }, + { 0x2c, 0x0031, }, + { 0x31, 0x010d, }, + { 0x32, 0x0100, }, + { 0x44, 0x0510, }, + { 0x54, 0x0104, }, + { 0x58, 0x2222, }, + { 0x59, 0x1162, }, + { 0x5a, 0x3211, }, + { 0x5d, 0x0370, }, + { 0x5e, 0x0296, }, + { 0x61, 0x0010, }, + { 0x63, 0x4a00, }, + { 0x65, 0x0800, }, + { 0x71, 0x0003, }, + { 0x72, 0x0470, }, + { 0x81, 0x0002, }, + { 0x82, 0x0600, }, + { 0x86, 0x0002, }, + { 0x8a, 0x2c38, }, + { 0x8b, 0x2a37, }, + { 0x92, 0x302f, }, + { 0x93, 0x3332, }, + { 0x96, 0x000c, }, + { 0x99, 0x0101, }, + { 0x9c, 0x2e37, }, + { 0x9d, 0x2c37, }, + { 0x9e, 0x2c37, }, + { 0xab, 0x0100, }, + { 0xac, 0x1003, }, + { 0xad, 0x103f, }, + { 0xe2, 0x0100, }, + { 0x28, 0x1010, }, + { 0xb1, 0x000e, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 1023, 770, }, + { 923, 300, }, + { 918, 295, }, + { 915, 290, }, + { 911, 285, }, + { 906, 280, }, + { 901, 275, }, + { 896, 270, }, + { 891, 265, }, + { 885, 260, }, + { 879, 255, }, + { 873, 250, }, + { 864, 245, }, + { 858, 240, }, + { 850, 235, }, + { 841, 230, }, + { 832, 225, }, + { 823, 220, }, + { 812, 215, }, + { 802, 210, }, + { 788, 205, }, + { 778, 200, }, + { 767, 195, }, + { 753, 190, }, + { 740, 185, }, + { 725, 180, }, + { 707, 175, }, + { 689, 170, }, + { 671, 165, }, + { 656, 160, }, + { 637, 155, }, + { 616, 150, }, + { 542, 145, }, + { 519, 140, }, + { 507, 135, }, + { 497, 130, }, + { 492, 125, }, + { 474, 120, }, + { 300, 111, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 12, 300, }, + { 15, 290, }, + { 18, 280, }, + { 22, 270, }, + { 23, 268, }, + { 24, 266, }, + { 25, 264, }, + { 27, 262, }, + { 28, 260, }, + { 29, 258, }, + { 30, 256, }, + { 32, 254, }, + { 33, 252, }, + { 34, 250, }, + { 35, 249, }, + { 36, 248, }, + { 37, 247, }, + { 38, 246, }, + { 39, 245, }, + { 40, 244, }, + { 41, 243, }, + { 42, 241, }, + { 43, 240, }, + { 44, 239, }, + { 45, 238, }, + { 46, 237, }, + { 47, 236, }, + { 48, 235, }, + { 49, 234, }, + { 50, 233, }, + { 51, 232, }, + { 52, 231, }, + { 53, 230, }, + { 55, 229, }, + { 56, 228, }, + { 57, 227, }, + { 58, 226, }, + { 59, 225, }, + { 60, 224, }, + { 62, 223, }, + { 63, 222, }, + { 65, 221, }, + { 66, 220, }, + { 68, 219, }, + { 69, 218, }, + { 70, 217, }, + { 72, 216, }, + { 73, 215, }, + { 75, 214, }, + { 76, 213, }, + { 78, 212, }, + { 80, 211, }, + { 81, 210, }, + { 83, 209, }, + { 84, 208, }, + { 85, 207, }, + { 87, 206, }, + { 89, 205, }, + { 91, 204, }, + { 93, 203, }, + { 95, 202, }, + { 96, 201, }, + { 104, 200, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 12, 400, }, + { 13, 390, }, + { 15, 380, }, + { 17, 360, }, + { 19, 350, }, + { 22, 348, }, + { 23, 346, }, + { 24, 344, }, + { 25, 342, }, + { 26, 340, }, + { 27, 336, }, + { 28, 334, }, + { 29, 332, }, + { 30, 330, }, + { 31, 328, }, + { 32, 326, }, + { 33, 325, }, + { 34, 322, }, + { 35, 320, }, + { 37, 318, }, + { 39, 316, }, + { 40, 314, }, + { 41, 312, }, + { 42, 310, }, + { 43, 308, }, + { 46, 306, }, + { 47, 304, }, + { 49, 302, }, + { 51, 300, }, + { 53, 298, }, + { 54, 297, }, + { 55, 296, }, + { 56, 295, }, + { 57, 294, }, + { 59, 293, }, + { 60, 292, }, + { 61, 291, }, + { 63, 290, }, + { 64, 289, }, + { 65, 288, }, + { 66, 287, }, + { 68, 286, }, + { 69, 285, }, + { 71, 284, }, + { 72, 283, }, + { 74, 282, }, + { 75, 281, }, + { 76, 280, }, + { 77, 279, }, + { 78, 278, }, + { 81, 277, }, + { 83, 276, }, + { 84, 275, }, + { 86, 274, }, + { 87, 273, }, + { 89, 272, }, + { 90, 271, }, + { 92, 270, }, + { 93, 269, }, + { 95, 268, }, + { 96, 267, }, + { 98, 266, }, + { 100, 265, }, + { 102, 264, }, + { 104, 263, }, + { 105, 262, }, + { 106, 261, }, + { 110, 260, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) +{ + int ret; + u8 buf [] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", + __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0, 0 }; + + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) + ; + return (b1[0] << 8) | b1[1]; +} + +static int s5h1409_softreset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + s5h1409_writereg(state, 0xf5, 0); + s5h1409_writereg(state, 0xf5, 1); + return 0; +} + +static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) +{ + struct s5h1409_state* state = fe->demodulator_priv; + int ret = 0; + + dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); + + if( (KHz == 44000) || (KHz == 5380) ) + { + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + } else { + printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); + ret = -1; + } + + return ret; +} + +static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + if(inverted == 1) + return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ + else + return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ +} + +static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __FUNCTION__, m); + + switch(m) { + case VSB_8: + dprintk("%s() VSB_8\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 0); + break; + case QAM_64: + dprintk("%s() QAM_64\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x100); + break; + case QAM_256: + dprintk("%s() QAM_256\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x101); + break; + default: + dprintk("%s() Invalid modulation\n", __FUNCTION__); + return -EINVAL; + } + + state->current_modulation = m; + s5h1409_softreset(fe); + + return 0; +} + +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xf3, 1); + else + return s5h1409_writereg(state, 0xf3, 0); +} + +static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xe3, 0x1100); + else + return s5h1409_writereg(state, 0xe3, 0); +} + +static int s5h1409_sleep(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + return s5h1409_writereg(state, 0xf2, enable); +} + +static int s5h1409_register_reset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + return s5h1409_writereg(state, 0xfa, 0); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency); + + s5h1409_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1409_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1409_init (struct dvb_frontend* fe) +{ + int i; + + struct s5h1409_state* state = fe->demodulator_priv; + dprintk("%s()\n", __FUNCTION__); + + s5h1409_sleep(fe, 0); + s5h1409_register_reset(fe); + + for (i=0; icurrent_modulation = VSB_8; + + if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) + s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + else + s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + + s5h1409_set_spectralinversion(fe, state->config->inversion); + s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_softreset(fe); + + /* Note: Leaving the I2C gate open here. */ + s5h1409_i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Get the demodulator status */ + reg = s5h1409_readreg(state, 0xf1); + if(reg & 0x1000) + *status |= FE_HAS_VITERBI; + if(reg & 0x8000) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + switch(state->config->status_mode) { + case S5H1409_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1409_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __FUNCTION__, *status); + + return 0; +} + +static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __FUNCTION__, *snr); + return ret; +} + +static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __FUNCTION__); + + reg = s5h1409_readreg(state, 0xf1) & 0x1ff; + + switch(state->current_modulation) { + case QAM_64: + return s5h1409_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + return s5h1409_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + return s5h1409_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + return s5h1409_read_snr(fe, signal_strength); +} + +static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + *ucblocks = s5h1409_readreg(state, 0xb5); + + return 0; +} + +static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) +{ + return s5h1409_read_ucblocks(fe, ber); +} + +static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1409_release(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1409_ops; + +struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + struct s5h1409_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = 0; + + /* check if the demod exists */ + if (s5h1409_readreg(state, 0x04) != 0x0066) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Note: Leaving the I2C gate open here. */ + s5h1409_writereg(state, 0xf3, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1409_ops = { + + .info = { + .name = "Samsung S5H1409 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1409_init, + .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, + .set_frontend = s5h1409_set_frontend, + .get_frontend = s5h1409_get_frontend, + .get_tune_settings = s5h1409_get_tune_settings, + .read_status = s5h1409_read_status, + .read_ber = s5h1409_read_ber, + .read_signal_strength = s5h1409_read_signal_strength, + .read_snr = s5h1409_read_snr, + .read_ucblocks = s5h1409_read_ucblocks, + .release = s5h1409_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1409_attach); diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h new file mode 100644 index 000000000000..6e9b9f24b60c --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -0,0 +1,68 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef S5H1409_H +#define S5H1409_H + +#include + +struct s5h1409_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define S5H1409_PARALLEL_OUTPUT 0 +#define S5H1409_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1409_GPIO_OFF 0 +#define S5H1409_GPIO_ON 1 + u8 gpio; + + /* IF Freq in KHz */ + u16 if_freq; + + /* Spectral Inversion */ +#define S5H1409_INVERSION_OFF 0 +#define S5H1409_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1409_TUNERLOCKING 0 +#define S5H1409_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_S5H1409 + +#endif // S5H1409_H From a45c92756ed60bc89528701ac512e954acd23b9e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 21 Mar 2007 12:03:23 -0300 Subject: [PATCH 034/310] V4L/DVB (5949): s5h1409: use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 4b77390f5d4b..25cf78142d94 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -476,7 +476,7 @@ static int s5h1409_init (struct dvb_frontend* fe) s5h1409_sleep(fe, 0); s5h1409_register_reset(fe); - for (i=0; i vsb_snr_tab[i].val) { *snr = vsb_snr_tab[i].data; ret = 0; From 3873dd041465799cfdeb642531c0ade4fb6614e5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 28 Jul 2007 20:02:55 -0300 Subject: [PATCH 035/310] V4L/DVB (5950): whitespace cleanup for mt2131 and s5h1409 - trivial whitespace cleanups - add "c-basic-offset: 8" to enforce tabbing style in emacs Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 46 +++++++++++++++------- drivers/media/dvb/frontends/mt2131.h | 9 ++++- drivers/media/dvb/frontends/mt2131_priv.h | 11 ++++-- drivers/media/dvb/frontends/s5h1409.c | 48 +++++++++++++++-------- drivers/media/dvb/frontends/s5h1409.h | 15 ++++--- 5 files changed, 88 insertions(+), 41 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 4fe1e62c9f06..375dfa166817 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -53,8 +53,10 @@ static u8 mt2131_config2[] = { static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) { struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, }; if (i2c_transfer(priv->i2c, msg, 2) != 2) { @@ -67,7 +69,8 @@ static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) { u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { printk(KERN_WARNING "mt2131 I2C write failed\n"); @@ -78,10 +81,12 @@ static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) { - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); return -EREMOTEIO; } return 0; @@ -98,14 +103,15 @@ static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) return 0; } -static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2131_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { struct mt2131_priv *priv; int ret=0, i; u32 freq; u8 if_band_center; - u32 f_lo1,f_lo2; - u32 div1,num1,div2,num2; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; u8 b[8]; u8 lockval = 0; @@ -231,7 +237,8 @@ static int mt2131_init(struct dvb_frontend *fe) int ret; dprintk(1, "%s()\n", __FUNCTION__); - if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) return ret; mt2131_writereg(priv, 0x0b, 0x09); @@ -239,7 +246,8 @@ static int mt2131_init(struct dvb_frontend *fe) mt2131_writereg(priv, 0x07, 0xf2); mt2131_writereg(priv, 0x0b, 0x01); - if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) return ret; return ret; @@ -270,7 +278,9 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = { .get_status = mt2131_get_status }; -struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) { struct mt2131_priv *priv = NULL; u8 id = 0; @@ -290,13 +300,16 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter return NULL; } if ( (id != 0x3E) && (id != 0x3F) ) { - printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); kfree(priv); return NULL; } - printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); fe->tuner_priv = priv; return fe; @@ -306,3 +319,8 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 5d1f281d87b2..608f1f66c9e7 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -44,6 +44,11 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2131 +#endif /* CONFIG_DVB_TUNER_MT2131 */ -#endif // __MT2131_H__ +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h index fe6333b49c93..e930759c2c00 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef MT2131_PRIV_H -#define MT2131_PRIV_H +#ifndef __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ /* Regs */ #define MT2131_PWR 0x07 @@ -41,4 +41,9 @@ struct mt2131_priv { u32 bandwidth; }; -#endif +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 25cf78142d94..30e8a705fad4 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -296,13 +296,14 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) int ret; u8 buf [] = { reg, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", - __FUNCTION__, reg, data, ret); + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -1 : 0; } @@ -314,14 +315,15 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) u8 b1 [] = { 0, 0 }; struct i2c_msg msg [] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 2 } }; ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) - ; + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return (b1[0] << 8) | b1[1]; } @@ -343,8 +345,7 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - if( (KHz == 44000) || (KHz == 5380) ) - { + if( (KHz == 44000) || (KHz == 5380) ) { s5h1409_writereg(state, 0x87, 0x01be); s5h1409_writereg(state, 0x88, 0x0436); s5h1409_writereg(state, 0x89, 0x054d); @@ -368,7 +369,8 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ } -static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +static int s5h1409_enable_modulation(struct dvb_frontend* fe, + fe_modulation_t m) { struct s5h1409_state* state = fe->demodulator_priv; @@ -443,7 +445,8 @@ static int s5h1409_register_reset(struct dvb_frontend* fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_set_frontend (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -521,11 +524,13 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) case S5H1409_TUNERLOCKING: /* Get the tuner status */ if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.get_status(fe, &tuner_status); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } if (tuner_status) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; @@ -605,7 +610,8 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) return -EINVAL; } -static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, + u16* signal_strength) { return s5h1409_read_snr(fe, signal_strength); } @@ -624,7 +630,8 @@ static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -634,7 +641,8 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; @@ -668,7 +676,8 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &s5h1409_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* Note: Leaving the I2C gate open here. */ @@ -713,3 +722,8 @@ MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(s5h1409_attach); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 6e9b9f24b60c..bccfd8a6fbd4 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -19,8 +19,8 @@ */ -#ifndef S5H1409_H -#define S5H1409_H +#ifndef __S5H1409_H__ +#define __S5H1409_H__ #include @@ -58,11 +58,16 @@ extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c) + struct i2c_adapter* i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_S5H1409 +#endif /* CONFIG_DVB_S5H1409 */ -#endif // S5H1409_H +#endif /* __S5H1409_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ From b2a657603e7285bf05b86ad198111b5403c57b41 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 16:35:32 -0300 Subject: [PATCH 036/310] V4L/DVB (5953): msp3400-driver.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 11cfcf18ec34..e9d400e19a5d 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -813,8 +813,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_rom; client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) + if (!client) return -ENOMEM; + client->addr = address; client->adapter = adapter; client->driver = &i2c_driver; @@ -826,14 +827,14 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) return 0; } - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { kfree(client); return -ENOMEM; } + i2c_set_clientdata(client, state); - memset(state, 0, sizeof(*state)); state->v4l2_std = V4L2_STD_NTSC; state->audmode = V4L2_TUNER_MODE_STEREO; state->volume = 58880; /* 0db gain */ From b6884a17fc70e979ef34e4b5560988b522bb50a0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 27 Jul 2007 10:08:51 -0300 Subject: [PATCH 037/310] V4L/DVB (5954): Sync with DiBcom Driver Release 2.1.3 + some improvements This changesets syncs the OpenSource driver for DiBcom demodulators with version 2.1.3 of DiBcom reference driver. There were some improvements since the last release for linux-dvb, e.g.: - stepped AGC startup - less space for initialization - diversity synchronization Furthermore this changeset contains the following things: - latest AGC settings for MT2266-based devices (namely Nova-TD and other) will improve the sensitivity - support for STK7700D reference design in dib0700-devices - remove some line-breaks when debugging is enabled - getting rid of layer between frontend_parameters and ofdm_channel used in dib*-drivers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 136 ++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/frontends/dib3000mc.c | 170 ++-- drivers/media/dvb/frontends/dib7000m.c | 719 +++++++++------ drivers/media/dvb/frontends/dib7000p.c | 886 +++++++++++++------ drivers/media/dvb/frontends/dib7000p.h | 7 +- drivers/media/dvb/frontends/dibx000_common.h | 57 +- drivers/media/dvb/frontends/mt2266.c | 4 +- 8 files changed, 1282 insertions(+), 698 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 122d9d4b4baa..04b66f6e659f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -4,7 +4,7 @@ * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * - * Copyright (C) 2005-6 DiBcom, SA + * Copyright (C) 2005-7 DiBcom, SA */ #include "dib0700.h" @@ -99,41 +99,87 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* STK7700D: Pinnacle Dual DVB-T Diversity */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { - BAND_UHF/* | BAND_VHF*/, - 0xE64, // setup - 2372, // inv_gain - 21, // time_stabiliz +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, // band_caps - 0, // alpha_level - 118, // thlock + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - 0, // wbd_inv - 0, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha + 1130, // inv_gain + 21, // time_stabiliz - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 + 0, // alpha_level + 118, // thlock - 17, // alpha_mant - 27, // alpha_exp + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha - 23, // beta_mant - 51, // beta_exp + 65535, // agc1_max + 33770, // agc1_min + 65535, // agc2_max + 23592, // agc2_min - 0, // perform_agc_softsplit : 1 en vrai! + 0, // agc1_pt1 + 62, // agc1_pt2 + 255, // agc1_pt3 + 64, // agc1_slope1 + 64, // agc1_slope2 + 132, // agc2_pt1 + 192, // agc2_pt2 + 80, // agc2_slope1 + 80, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + }, { + BAND_VHF | BAND_LBAND, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { @@ -150,23 +196,25 @@ static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }, { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, } }; @@ -211,7 +259,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -241,7 +289,7 @@ int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) #define KEY_MAP_SIZE (25+48) -struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key stk7700d_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -436,6 +484,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = { static struct dib7000p_config stk7700p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, + .agc_config_count = 1, .agc = &stk7700p_7000p_mt2060_agc_config, .bw = &stk7700p_pll_config, @@ -506,6 +555,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -615,7 +665,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Pinnacle PCTV 2000e", { &dib0700_usb_id_table[11], NULL }, @@ -629,6 +679,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[13], NULL }, { NULL }, }, + { "DiBcom STK7700D", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = stk7700d_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2e38be3aa45b..5657ad8beaac 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -67,6 +67,7 @@ #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 054d7e6d9662..cbbe2c2f05dc 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,7 +1,7 @@ /* * Driver for DiBcom DiB3000MC/P-demodulator. * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . @@ -26,7 +26,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { struct dvb_frontend demod; @@ -71,7 +71,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } - static int dib3000mc_identify(struct dib3000mc_state *state) { u16 value; @@ -92,7 +91,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state) return 0; } -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset) +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) { u32 timf; @@ -103,7 +102,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, } else timf = state->timf; - timf *= (BW_INDEX_TO_KHZ(bw) / 1000); + timf *= (bw / 1000); if (update_offset) { s16 tim_offs = dib3000mc_read_word(state, 416); @@ -111,17 +110,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, if (tim_offs & 0x2000) tim_offs -= 0x4000; - if (nfft == 0) + if (nfft == TRANSMISSION_MODE_2K) tim_offs *= 4; timf += tim_offs; - state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000); + state->timf = timf / (bw / 1000); } dprintk("timf: %d\n", timf); - dib3000mc_write_word(state, 23, timf >> 16); - dib3000mc_write_word(state, 24, timf & 0xffff); + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); return 0; } @@ -209,31 +208,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) return ret; } -static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) { - struct dib3000mc_state *state = demod->demodulator_priv; u16 bw_cfg[6] = { 0 }; u16 imp_bw_cfg[3] = { 0 }; u16 reg; /* settings here are for 27.7MHz */ switch (bw) { - case BANDWIDTH_8_MHZ: + case 8000: bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; break; - case BANDWIDTH_7_MHZ: + case 7000: bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; break; - case BANDWIDTH_6_MHZ: + case 6000: bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; break; - case 255 /* BANDWIDTH_5_MHZ */: + case 5000: bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; break; @@ -257,7 +255,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); // Timing configuration - dib3000mc_set_timing(state, 0, bw, 0); + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); return 0; } @@ -276,7 +274,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, for (i = 58; i < 87; i++) dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - if (nfft == 1) { + if (nfft == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 58, 0x3b); dib3000mc_write_word(state, 84, 0x00); dib3000mc_write_word(state, 85, 0x8200); @@ -376,7 +374,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) // P_search_maxtrial=1 dib3000mc_write_word(state, 5, 1); - dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib3000mc_set_bandwidth(state, 8000); // div_lock_mask dib3000mc_write_word(state, 4, 0x814); @@ -397,7 +395,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) dib3000mc_write_word(state, 180, 0x2FF0); // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, 1); + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); // output mode set-up dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); @@ -423,13 +421,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) { u16 cfg[4] = { 0 },reg; switch (qam) { - case 0: + case QPSK: cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; break; - case 1: + case QAM_16: cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; break; - case 2: + case QAM_64: cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; break; } @@ -437,11 +435,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) { - u16 tmp; - - dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0); + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -455,7 +453,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 26, 0x6680); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, 1); + dib3000mc_set_adp_cfg(state, QAM_16); dib3000mc_write_word(state, 133, 15564); dib3000mc_write_word(state, 12 , 0x0); @@ -470,52 +468,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, chan->nfft); - - tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha; - dib3000mc_write_word(state, 0, tmp); + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp); - if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp)) - tmp |= chan->vit_code_rate_hp << 1; - else - tmp |= chan->vit_code_rate_lp << 1; - dib3000mc_write_word(state, 181, tmp); + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); - // diversity synchro delay - tmp = dib3000mc_read_word(state, 180) & 0x000f; - tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin - dib3000mc_write_word(state, 180, tmp); + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); // restart demod - tmp = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, tmp | (1 << 9)); - dib3000mc_write_word(state, 0, tmp); + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) { struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dibx000_ofdm_channel fchan; + struct dvb_frontend_parameters schan; - INIT_OFDM_CHANNEL(&fchan); - fchan = *chan; + schan = *chan; + /* TODO what is that ? */ /* a channel for autosearch */ - fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2; - fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; - fchan.vit_hrch = 0; fchan.vit_select_hp = 1; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; - dib3000mc_set_channel_cfg(state, &fchan, 11); + dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); @@ -539,7 +583,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib3000mc_state *state = demod->demodulator_priv; @@ -549,9 +593,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (u8)ch->nqam); - - if (ch->nfft == 1) { + dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -560,7 +603,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0; } @@ -632,13 +675,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); @@ -651,7 +690,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 100, found; - dib3000mc_autosearch_start(fe, &ch); + dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -662,13 +701,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, return 0; // no channel found dib3000mc_get_frontend(fe, fep); - FEP2DIB(fep,&ch); } /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib3000mc_tune(fe, &ch); + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index f64546c6aeb5..608156a691de 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -2,7 +2,7 @@ * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,7 +19,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -39,8 +39,16 @@ struct dib7000m_state { fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; + u32 timf_default; + u32 internal_clk; + + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; u16 revision; + + u8 agc_state; }; enum dib7000m_power_mode { @@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) { int ret = 0; @@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } return ret; } -static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) { /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - /* P_sdio_select_clk = 0 on MC */ + /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; - dib7000m_write_word(state, 903, reg_903); - dib7000m_write_word(state, 904, reg_904); - dib7000m_write_word(state, 905, reg_905); - dib7000m_write_word(state, 906, reg_906); + if (state->revision == 0x4003) + offset = 1; - return 0; + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); } static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) @@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914); - +// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret; } -static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx) +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { - struct dib7000m_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = bw_idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); - timf = state->cfg.bw->timf; + dprintk( "using default timf"); + timf = state->timf_default; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dib7000m_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000m_write_word(state, 24, (timf ) & 0xffff); + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } return 0; } @@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) { - dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff); - dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000m_write_word(state, 22, bw->ifreq & 0xffff); + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg); } @@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state) static void dib7000mc_reset_pll(struct dib7000m_state *state) { const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0)); + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); @@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state) static int dib7000m_reset_gpio(struct dib7000m_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n", - st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos); - dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); @@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st) return 0; } +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + static int dib7000m_demod_reset(struct dib7000m_state *state) { dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); @@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib7000m_set_bandwidth(state, 8000); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000m_sad_calib(state); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + state->internal_clk = state->cfg.bw->internal; + return 0; } @@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d\n",split_offset); + dprintk( "AGC split_offset: %d",split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) static int dib7000m_update_lna(struct dib7000m_state *state) { - int i; u16 dyn_gain; - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return 0; - - msleep(60); - for (i = 0; i < 20; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000m_read_word(state, 390); - dprintk("agc global: %d\n", dyn_gain); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000m_restart_agc(state); - msleep(60); - } else - break; + return 1; + } } return 0; } -static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; - if (state->current_band == band) - return; + if (state->current_band == band && state->current_agc != NULL) + return 0; state->current_band = band; for (i = 0; i < state->cfg.agc_config_count; i++) @@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band); - return; + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } state->current_agc = agc; @@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk("-D- 929: %x %d %d\n", +// dprintk( "929: %x %d %d", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) for (i = 0; i < 9; i++) dib7000m_write_word(state, 88 + i, b[i]); } + return 0; } -static void dib7000m_update_timf_freq(struct dib7000m_state *state) +static void dib7000m_update_timf(struct dib7000m_state *state) { u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; +} + +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); dib7000m_write_word(state, 5, (seq << 4)); - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - value |= (ch->vit_code_rate_hp << 1); - else - value |= (ch->vit_code_rate_lp << 1); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } dib7000m_write_word(state, 267 + state->reg_offs, value); /* offset loop parameters */ @@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: value = 256; break; - case 2: value = 128; break; - case 0: + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: default: value = 64; break; } - value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - value <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || state->revision > 0x4000) - value |= (1 << 2) | (2 << 0); + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; else - value |= 0; - dib7000m_write_word(state, 266 + state->reg_offs, value); + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of for (value = 0; value < 4; value++) dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - msleep(7); - - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000m_update_lna(state); - dib7000m_agc_soft_split(state); - - // wait AGC accurate lock time - msleep(7); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - // set power-up level: autosearch dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; + struct dvb_frontend_parameters schan; int ret = 0; - u32 value; + u32 value, factor; - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; + schan = *ch; - dib7000m_set_channel(state, &auto_ch, 7); + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, value | (1 << 9)); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) @@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk("#\n"); + dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk("!\n"); + dprintk( "autosearch succeeded"); return 2; } return 0; // still pending @@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; @@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); - ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - // never achieved a lock with that bandwidth so far - wait for timfreq to update + // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: value |= (7 << 12); break; - case 1: value |= (9 << 12); break; - case 2: value |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case /* 4K MODE */ 255: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); - // we achieved a lock - it's time to update the osc freq + // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf_freq(state); + dib7000m_update_timf(state); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret; } -static int dib7000m_init(struct dvb_frontend *demod) +static int dib7000m_wakeup(struct dvb_frontend *demod) { struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u8 o = state->reg_offs; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("-E- could not start Slow ADC\n"); + dprintk( "could not start Slow ADC"); - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - ret |= dib7000m_write_word(state, 261 + o, 2); - else - ret |= dib7000m_write_word(state, 224 + o, 1); - - ret |= dib7000m_write_word(state, 173 + o, 0); - ret |= dib7000m_write_word(state, 174 + o, 0); - ret |= dib7000m_write_word(state, 175 + o, 0); - ret |= dib7000m_write_word(state, 176 + o, 0); - ret |= dib7000m_write_word(state, 177 + o, 0); - ret |= dib7000m_write_word(state, 178 + o, 0); - ret |= dib7000m_write_word(state, 179 + o, 0); - ret |= dib7000m_write_word(state, 180 + o, 0); - - // P_corm_thres Lock algorithms configuration - ret |= dib7000m_write_word(state, 26, 0x6680); - - // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - ret |= dib7000m_write_word(state, 170 + o, 0x0410); - // P_fft_nb_to_cut - ret |= dib7000m_write_word(state, 182 + o, 8192); - // P_pha3_thres - ret |= dib7000m_write_word(state, 195 + o, 0x0ccd); - // P_cti_use_cpe, P_cti_use_prog - ret |= dib7000m_write_word(state, 196 + o, 0); - // P_cspu_regul, P_cspu_win_cut - ret |= dib7000m_write_word(state, 205 + o, 0x200f); - // P_adp_regul_cnt - ret |= dib7000m_write_word(state, 214 + o, 0x023d); - // P_adp_noise_cnt - ret |= dib7000m_write_word(state, 215 + o, 0x00a4); - // P_adp_regul_ext - ret |= dib7000m_write_word(state, 216 + o, 0x00a4); - // P_adp_noise_ext - ret |= dib7000m_write_word(state, 217 + o, 0x7ff0); - // P_adp_fil - ret |= dib7000m_write_word(state, 218 + o, 0x3ccc); - - // P_2d_byp_ti_num - ret |= dib7000m_write_word(state, 226 + o, 0); - - // P_fec_* - ret |= dib7000m_write_word(state, 281 + o, 0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000m_write_word(state, 294 + o,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000m_write_word(state, 36, 0x0755); - else - ret |= dib7000m_write_word(state, 36, 0x1f55); - - // auto search configuration - ret |= dib7000m_write_word(state, 2, 0x0004); - ret |= dib7000m_write_word(state, 3, 0x1000); - ret |= dib7000m_write_word(state, 4, 0x0814); - ret |= dib7000m_write_word(state, 6, 0x001b); - ret |= dib7000m_write_word(state, 7, 0x7740); - ret |= dib7000m_write_word(state, 8, 0x005b); - ret |= dib7000m_write_word(state, 9, 0x8d80); - ret |= dib7000m_write_word(state, 10, 0x01c9); - ret |= dib7000m_write_word(state, 11, 0xc380); - ret |= dib7000m_write_word(state, 12, 0x0000); - ret |= dib7000m_write_word(state, 13, 0x0080); - ret |= dib7000m_write_word(state, 14, 0x0000); - ret |= dib7000m_write_word(state, 15, 0x0090); - ret |= dib7000m_write_word(state, 16, 0x0001); - ret |= dib7000m_write_word(state, 17, 0xd4c0); - ret |= dib7000m_write_word(state, 263 + o,0x0001); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - // Tuner IO bank: max drive (14mA) - ret |= dib7000m_write_word(state, 912 ,0x2c8a); - - ret |= dib7000m_write_word(state, 1817, 1); - - return ret; + return 0; } static int dib7000m_sleep(struct dvb_frontend *demod) { struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) | - dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF); } static int dib7000m_identify(struct dib7000m_state *state) { u16 value; + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && - state->revision != 0x4002) { - dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value); + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n"); + dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break; - case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break; - case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break; + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0; @@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, &ch); + dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000m_tune(fe, &ch); + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified\n", k); + dprintk("DiB7000M #%d: not identified", k); return -EIO; } } @@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1172,7 +1381,7 @@ static struct dvb_frontend_ops dib7000m_ops = { .release = dib7000m_release, - .init = dib7000m_init, + .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index c24189fcbc89..156c53ab56db 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1,7 +1,7 @@ /* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +18,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { struct dvb_frontend demod; @@ -36,12 +36,19 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; + + u8 agc_state; + u16 gpio_dir; u16 gpio_val; }; enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY, }; @@ -55,7 +62,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -71,6 +78,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { int ret = 0; @@ -80,7 +103,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { @@ -104,19 +127,17 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } - if (state->cfg.hostbus_diversity) { - ret |= dib7000p_write_word(state, 204, 1); // Diversity ? - ret |= dib7000p_write_word(state, 205, 0); // Diversity ? - } - if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; @@ -127,6 +148,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) return ret; } +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + dib7000p_write_word(state, 207, 0); + } + + return 0; +} + static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ @@ -139,10 +184,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + reg_1280 &= ~((1 << 11)); + /* fall through wanted to enable the interfaces */ + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break; + /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } @@ -193,34 +249,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad break; } -// dprintk("908: %x, 909: %x\n", reg_908, reg_909); +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909); } -static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) { - struct dib7000p_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = BW_Idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); + dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dprintk("timf: %d\n",timf); - - dib7000p_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000p_write_word(state, 24, (timf ) & 0xffff); + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0; } @@ -228,7 +281,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 @@ -244,15 +297,24 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | + (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | - (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0)); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); - dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff); - dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff); + dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } @@ -260,7 +322,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -273,6 +335,98 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static u16 dib7000p_defaults[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + + 1, 168, + 0x0ccd, // P_pha3_thres, default 0x3000 + +// 1, 169, +// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + + 1, 183, + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 5, 187, + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 198, + 0x800, // P_equal_thres_wgn + + 1, 222, + 0x0010, // P_fec_ber_rs_len=2 + + 1, 235, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 2, 901, + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + + 1, 905, + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + + 0, +}; + static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); @@ -297,47 +451,34 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); + dib7000p_set_bandwidth(state, 8000); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36,0x0755); + else + dib7000p_write_word(state, 36,0x1f55); + + dib7000p_write_tab(state, dib7000p_defaults); + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return 0; } -static void dib7000p_restart_agc(struct dib7000p_state *state) -{ - // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, 0x0c00); - dib7000p_write_word(state, 770, 0x0000); -} - -static void dib7000p_update_lna(struct dib7000p_state *state) -{ - int i; - u16 dyn_gain; - - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return; - - for (i = 0; i < 5; i++) { - // read dyn_gain here (because it is demod-dependent and not tuner) - dyn_gain = dib7000p_read_word(state, 394); - - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed - dib7000p_restart_agc(state); - msleep(5); - } else - break; - } -} - static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) { u16 tmp = 0; @@ -347,61 +488,270 @@ static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock } -static void dib7000p_update_timf_freq(struct dib7000p_state *state) +static void dib7000p_restart_agc(struct dib7000p_state *state) { - u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); - dib7000p_write_word(state, 23, (u16) (timf >> 16)); - dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + // P_restart_iqc & P_restart_agc + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); + dib7000p_write_word(state, 770, 0x0000); } -static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000p_update_lna(struct dib7000p_state *state) { - u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208; + u16 dyn_gain; + + // when there is no LNA to program return immediatly + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not tuner) + dyn_gain = dib7000p_read_word(state, 394); + if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed + dib7000p_restart_agc(state); + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; + break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; + } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75 , agc->setup ); + dib7000p_write_word(state, 76 , agc->inv_gain ); + dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; +} + +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; + (*agc_state)++; + break; + + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; +} + +static void dib7000p_update_timf(struct dib7000p_state *state) +{ + u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); + state->timf = timf * 160 / (state->current_bandwidth / 50); + dib7000p_write_word(state, 23, (u16) (timf >> 16)); + dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + +} + +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) +{ + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000p_write_word(state, 0, value); dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - tmp |= (ch->vit_code_rate_hp << 1); - else - tmp |= (ch->vit_code_rate_lp << 1); - dib7000p_write_word(state, 208, tmp); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: tmp = 256; break; - case 2: tmp = 128; break; - case 0: - default: tmp = 64; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; } - tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - tmp <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - /* deactive the possibility of diversity reception if extended interleave */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || ch->nfft == 1) - tmp |= (1 << 2) | (2 << 0); - dib7000p_write_word(state, 207, tmp); - - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -414,66 +764,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ break; } - for (tmp = 0; tmp < 4; tmp++) - dib7000p_write_word(state, 187 + tmp, est[tmp]); - - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - msleep(7); - - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000p_update_lna(state); - - // wait AGC accurate lock time - msleep(7); - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; - u32 value; + struct dvb_frontend_parameters schan; + u32 value, factor; - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; - dib7000p_set_channel(state, &auto_ch, 7); + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (1 << 9) | value); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); dib7000p_read_word(state, 1284); dib7000p_write_word(state, 0, (u16) value); @@ -494,7 +823,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; + static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255}; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz; + int k; + int coef_re[8],coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + + if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142 ,0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + + if (pha==0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if(pha < 256) { + coef_re[k] = sine[256-(pha&0xff)]; + coef_im[k] = sine[pha&0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha&0xff]; + coef_im[k] = sine[256 - (pha&0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256-(pha&0xff)]; + coef_im[k] = -sine[pha&0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha&0xff]; + coef_im[k] = -sine[256 - (pha&0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1<<14); + if (coef_re[k] >= (1<<24)) + coef_re[k] = (1<<24) - 1; + coef_re[k] /= (1<<15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1<<14); + if (coef_im[k] >= (1<<24)) + coef_im[k] = (1<<24)-1; + coef_im[k] /= (1<<15); + + dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state,143 ,0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -520,28 +937,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: tmp |= (7 << 12); break; - case 1: tmp |= (9 << 12); break; - case 2: tmp |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; + case /* 4K MODE */ 255: tmp |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; } dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 33, tmp); @@ -557,131 +977,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel // we achieved a lock - it's time to update the osc freq if ((tmp >> 6) & 0x1) - dib7000p_update_timf_freq(state); + dib7000p_update_timf(state); + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } -static int dib7000p_init(struct dvb_frontend *demod) +static int dib7000p_wakeup(struct dvb_frontend *demod) { - struct dibx000_agc_config *agc; struct dib7000p_state *state = demod->demodulator_priv; - int ret = 0; - - // Demodulator default configuration - agc = state->cfg.agc; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - - /* AGC */ - ret |= dib7000p_write_word(state, 75 , agc->setup ); - ret |= dib7000p_write_word(state, 76 , agc->inv_gain ); - ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz ); - ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - - ret |= dib7000p_write_word(state, 107, agc->agc1_max); - ret |= dib7000p_write_word(state, 108, agc->agc1_min); - ret |= dib7000p_write_word(state, 109, agc->agc2_max); - ret |= dib7000p_write_word(state, 110, agc->agc2_min); - ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - ret |= dib7000p_write_word(state, 112, agc->agc1_pt3); - ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - /* disable power smoothing */ - ret |= dib7000p_write_word(state, 145, 0); - ret |= dib7000p_write_word(state, 146, 0); - ret |= dib7000p_write_word(state, 147, 0); - ret |= dib7000p_write_word(state, 148, 0); - ret |= dib7000p_write_word(state, 149, 0); - ret |= dib7000p_write_word(state, 150, 0); - ret |= dib7000p_write_word(state, 151, 0); - ret |= dib7000p_write_word(state, 152, 0); - - // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 - ret |= dib7000p_write_word(state, 26 ,0x6680); - - // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 - ret |= dib7000p_write_word(state, 142,0x0410); - // P_fft_freq_dir=1, P_fft_nb_to_cut=0 - ret |= dib7000p_write_word(state, 154,1 << 13); - // P_pha3_thres, default 0x3000 - ret |= dib7000p_write_word(state, 168,0x0ccd); - // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 - //ret |= dib7000p_write_word(state, 169,0x0010); - // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 - ret |= dib7000p_write_word(state, 183,0x200f); - // P_adp_regul_cnt=573, default: 410 - ret |= dib7000p_write_word(state, 187,0x023d); - // P_adp_noise_cnt= - ret |= dib7000p_write_word(state, 188,0x00a4); - // P_adp_regul_ext - ret |= dib7000p_write_word(state, 189,0x00a4); - // P_adp_noise_ext - ret |= dib7000p_write_word(state, 190,0x7ff0); - // P_adp_fil - ret |= dib7000p_write_word(state, 191,0x3ccc); - - ret |= dib7000p_write_word(state, 222,0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000p_write_word(state, 235,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000p_write_word(state, 36,0x0755); - else - ret |= dib7000p_write_word(state, 36,0x1f55); - - // auto search configuration - ret |= dib7000p_write_word(state, 2 ,0x0004); - ret |= dib7000p_write_word(state, 3 ,0x1000); - - /* Equal Lock */ - ret |= dib7000p_write_word(state, 4 ,0x0814); - - ret |= dib7000p_write_word(state, 6 ,0x001b); - ret |= dib7000p_write_word(state, 7 ,0x7740); - ret |= dib7000p_write_word(state, 8 ,0x005b); - ret |= dib7000p_write_word(state, 9 ,0x8d80); - ret |= dib7000p_write_word(state, 10 ,0x01c9); - ret |= dib7000p_write_word(state, 11 ,0xc380); - ret |= dib7000p_write_word(state, 12 ,0x0000); - ret |= dib7000p_write_word(state, 13 ,0x0080); - ret |= dib7000p_write_word(state, 14 ,0x0000); - ret |= dib7000p_write_word(state, 15 ,0x0090); - ret |= dib7000p_write_word(state, 16 ,0x0001); - ret |= dib7000p_write_word(state, 17 ,0xd4c0); - - // P_clk_cfg1 - ret |= dib7000p_write_word(state, 901, 0x0006); - - // P_divclksel=3 P_divbitsel=1 - ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); - - // Tuner IO bank: max drive (14mA) + divout pads max drive - ret |= dib7000p_write_word(state, 905, 0x2c8e); - - ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); - dib7000p_sad_calib(state); - - return ret; + return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) @@ -693,16 +1003,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n", + dprintk( "checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (read=0x%x)",value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value); + dprintk( "wrong Device ID (%x)",value); return -EREMOTEIO; } @@ -772,41 +1082,45 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, &ch); + dib7000p_autosearch_start(fe, fep); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000p_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000p_tune(fe, &ch); + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -884,7 +1198,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } @@ -892,11 +1206,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } - dprintk("-D- DiB7000PC not detected\n"); + dprintk("-D- DiB7000PC not detected"); return 0; } EXPORT_SYMBOL(dib7000pc_detection); @@ -934,7 +1248,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1005,7 +1319,7 @@ static struct dvb_frontend_ops dib7000p_ops = { .release = dib7000p_release, - .init = dib7000p_init, + .init = dib7000p_wakeup, .sleep = dib7000p_sleep, .set_frontend = dib7000p_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 94829c1ed054..e7769e7cd92a 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -9,6 +9,7 @@ struct dib7000p_config { u8 tuner_is_baseband; int (*update_lna) (struct dvb_frontend *, u16 agc_global); + u8 agc_config_count; struct dibx000_agc_config *agc; struct dibx000_bandwidth_config *bw; @@ -27,15 +28,19 @@ struct dib7000p_config { u8 quartz_direct; + u8 spur_protect; + int (*agc_control) (struct dvb_frontend *, u8 before); }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index a1df604366c3..5e17275afd25 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -111,6 +111,8 @@ struct dibx000_bandwidth_config { u32 ifreq; u32 timf; + + u32 xtal_hz; }; enum dibx000_adc_states { @@ -122,56 +124,17 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ +#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) /* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 - -/* I hope I can get rid of the following kludge in the near future */ -struct dibx000_ofdm_channel { - u32 RF_kHz; - u8 Bw; - s16 nfft; - s16 guard; - s16 nqam; - s16 vit_hrch; - s16 vit_select_hp; - s16 vit_alpha; - s16 vit_code_rate_hp; - s16 vit_code_rate_lp; - u8 intlv_native; -}; - -#define FEP2DIB(fep,ch) \ - (ch)->RF_kHz = (fep)->frequency / 1000; \ - (ch)->Bw = (fep)->u.ofdm.bandwidth; \ - (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \ - (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \ - (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \ - (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \ - (ch)->vit_select_hp = 1; \ - (ch)->vit_alpha = 1; \ - (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \ - (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \ - (ch)->intlv_native = 1; - -#define INIT_OFDM_CHANNEL(ch) do {\ - (ch)->Bw = 0; \ - (ch)->nfft = -1; \ - (ch)->guard = -1; \ - (ch)->nqam = -1; \ - (ch)->vit_hrch = -1; \ - (ch)->vit_select_hp = -1; \ - (ch)->vit_alpha = -1; \ - (ch)->vit_code_rate_hp = -1; \ - (ch)->vit_code_rate_lp = -1; \ -} while (0) +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 #endif diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 145135778bce..33b388e8f7b8 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -159,7 +159,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); b[0] = 0x05; @@ -176,7 +176,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame msleep(10); i++; } while (i<10); - dprintk("Lock when i=%i\n",(int)i); + dprintk("Lock when i=%i",(int)i); return ret; } From 01373a5c97ced83d4cb520f7e56c80454a198bfb Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 12:49:04 -0300 Subject: [PATCH 038/310] V4L/DVB (5955): Add support for DiB7070-based devices This changeset adds support for DiB7070P-based devices by adding the dib0070-driver and putting the appropriate layouts into dib0700_devices.c It also includes a new firmware for the dib0700 which is necessary to make the DiB7070-boards work and it also should fix the i2c-problems on some boards. Signed-off-by: Jean-Philippe Sibers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700_devices.c | 295 +++++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 10 +- drivers/media/dvb/frontends/Kconfig | 9 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib0070.c | 580 ++++++++++++++++++++ drivers/media/dvb/frontends/dib0070.h | 44 ++ drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000m.c | 12 +- drivers/media/dvb/frontends/dib7000p.c | 44 +- drivers/media/dvb/frontends/dib7000p.h | 9 +- 11 files changed, 974 insertions(+), 33 deletions(-) create mode 100644 drivers/media/dvb/frontends/dib0070.c create mode 100644 drivers/media/dvb/frontends/dib0070.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index dec03ee32e1a..d73934dd4c57 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -75,6 +75,7 @@ config DVB_USB_DIB0700 select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 04b66f6e659f..558ab3bd6889 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -13,13 +13,18 @@ #include "dib7000p.h" #include "mt2060.h" #include "mt2266.h" +#include "dib0070.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " "if applicable for the device (default: 0=automatic/off)."); -/* Hauppauge Nova-T 500 +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); +}; + +/* Hauppauge Nova-T 500 (aka Bristol) * has a LNA on GPIO0 which is enabled by setting 1 */ static struct mt2060_config bristol_mt2060_config[2] = { { @@ -97,7 +102,7 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } -/* STK7700D: Pinnacle Dual DVB-T Diversity */ +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ /* MT226x */ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { @@ -539,31 +544,243 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0]) == NULL ? -ENODEV : 0; } +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 600, // inv_gain + 10, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 5, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + + 65535, // agc2_max + 0, // agc2_min + + 0, // agc1_pt1 + 40, // agc1_pt2 + 183, // agc1_pt3 + 206, // agc1_slope1 + 255, // agc1_slope2 + 72, // agc2_pt1 + 152, // agc2_pt2 + 88, // agc2_slope1 + 90, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4 + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + + } +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, // internal, sampling + 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + (0 << 25) | 0, // ifreq = 0.000000 MHz + 20452225, // timf + 12000000, // xtal_hz +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, - { } /* Terminating entry */ +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-01.fw", \ + .firmware = "dvb-usb-dib0700-03-pre1.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ @@ -675,11 +892,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick", + { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, - { "DiBcom STK7700D", + { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, }, @@ -688,7 +905,65 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = stk7700d_rc_keys, .rc_key_map_size = KEY_MAP_SIZE, .rc_query = stk7700d_rc_query - } + + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + } + }, }; int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 5657ad8beaac..dae605bbd0f9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -68,6 +68,8 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7070P 0x1ebc +#define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 @@ -122,6 +124,11 @@ #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_PINNACLE_PCTV2000E 0x022c +#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 +#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_PCTV_450E 0x0222 #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 @@ -141,9 +148,6 @@ #define USB_PID_MSI_MEGASKY580_55801 0x5581 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 #define USB_PID_LITEON_DVB_T_COLD 0xf000 #define USB_PID_LITEON_DVB_T_WARM 0xf001 #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index faf9fe3c9cce..53e775539649 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -344,6 +344,15 @@ config DVB_TUNER_MT2131 help A driver for the silicon baseband tuner MT2131 from Microtune. +config DVB_TUNER_DIB0070 + tristate "DiBcom DiB0070 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0070 from DiBcom. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index c46b9d8e9313..4b8ad1f132aa 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c new file mode 100644 index 000000000000..481eaa684157 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.c @@ -0,0 +1,580 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ +#include +#include + +#include "dvb_frontend.h" + +#include "dib0070.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) + +#define DIB0070_P1D 0x00 +#define DIB0070_P1F 0x01 +#define DIB0070_P1G 0x03 +#define DIB0070S_P1A 0x02 + +struct dib0070_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0070_config *cfg; + u16 wbd_ff_offset; + u8 revision; +}; + +static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) +{ + u8 b[3] = { reg, val >> 8, val & 0xff }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) + +static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u16 tmp = 0; + tmp = dib0070_read_reg(st, 0x02) & 0x3fff; + + switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { + case 8000: + tmp |= (0 << 14); + break; + case 7000: + tmp |= (1 << 14); + break; + case 6000: + tmp |= (2 << 14); + break; + case 5000: + default: + tmp |= (3 << 14); + break; + } + dib0070_write_reg(st, 0x02, tmp); + return 0; +} + +static void dib0070_captrim(struct dib0070_state *st, u16 LO4) +{ + int8_t captrim, fcaptrim, step_sign, step; + u16 adc, adc_diff = 3000; + + + + dib0070_write_reg(st, 0x0f, 0xed10); + dib0070_write_reg(st, 0x17, 0x0034); + + dib0070_write_reg(st, 0x18, 0x0032); + msleep(2); + + step = captrim = fcaptrim = 64; + + do { + step /= 2; + dib0070_write_reg(st, 0x14, LO4 | captrim); + msleep(1); + adc = dib0070_read_reg(st, 0x19); + + dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < adc_diff) { + dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); + adc_diff = adc; + fcaptrim = captrim; + + + + } + captrim += (step_sign * step); + } while (step >= 1); + + dib0070_write_reg(st, 0x14, LO4 | fcaptrim); + dib0070_write_reg(st, 0x18, 0x07ff); +} + +#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) +#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) +#define LO4_SET_CTRIM(l, c) l |= (c) << 10 +static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); + + u8 band = BAND_OF_FREQUENCY(freq), c; + + /*******************VCO***********************************/ + u16 lo4 = 0; + + u8 REFDIV, PRESC = 2; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u16 Num, Den; + /*******************FrontEnd******************************/ + u16 value = 0; + + dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); + + + dib0070_write_reg(st, 0x17, 0x30); + + dib0070_set_bandwidth(fe, ch); /* c is used as HF */ + switch (st->revision) { + case DIB0070S_P1A: + switch (band) { + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 2; + break; + case BAND_SBAND: + LO4_SET_VCO_HFDIV(lo4, 0, 0); + LO4_SET_CTRIM(lo4, 1);; + c = 1; + break; + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + PRESC = 6; c = 6; + } else if (freq < 680000) { + LO4_SET_VCO_HFDIV(lo4, 0, 2); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 2); + c = 4; + } + break; + } break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + switch (band) { + case BAND_FM: + LO4_SET_VCO_HFDIV(lo4, 0, 7); + c = 24; + break; + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 0); + c = 2; + break; + case BAND_VHF: + if (freq < 180000) { + LO4_SET_VCO_HFDIV(lo4, 0, 3); + c = 16; + } else if (freq < 190000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + c = 16; + } else { + LO4_SET_VCO_HFDIV(lo4, 0, 6); + c = 12; + } + break; + + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 5); + c = 6; + } else if (freq < 700000) { + LO4_SET_VCO_HFDIV(lo4, 0, 1); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 4; + } + break; + } + break; + } + + dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); + dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); + + + VCOF_kHz = (c * freq) * 2; + dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((st->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) ( st->cfg->clock_khz / 10000); + break; + } + FREF = st->cfg->clock_khz / REFDIV; + + dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); + + + + switch (st->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / PRESC / FREF); + Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + + if (Rest < LPF) Rest = 0; + else if (Rest < 2 * LPF) Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } + else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); + + Num = 0; + Den = 1; + + if (Rest > 0) { + LO4_SET_SD(lo4, 1); + Den = 255; + Num = (u16)Rest; + } + dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); + + + + dib0070_write_reg(st, 0x11, (u16)FBDiv); + + + dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); + + + dib0070_write_reg(st, 0x13, Num); + + + value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; + + switch (band) { + case BAND_UHF: value |= 0x4000 | 0x0800; break; + case BAND_LBAND: value |= 0x2000 | 0x0400; break; + default: value |= 0x8000 | 0x1000; break; + } + dib0070_write_reg(st, 0x20, value); + + dib0070_captrim(st, lo4); + if (st->revision == DIB0070S_P1A) { + if (band == BAND_SBAND) + dib0070_write_reg(st, 0x15, 0x16e2); + else + dib0070_write_reg(st, 0x15, 0x56e5); + } + + + + switch (band) { + case BAND_UHF: value = 0x7c82; break; + case BAND_LBAND: value = 0x7c84; break; + default: value = 0x7c81; break; + } + dib0070_write_reg(st, 0x0f, value); + dib0070_write_reg(st, 0x06, 0x3fff); + + /* Front End */ + /* c == TUNE, value = SWITCH */ + c = 0; + value = 0; + switch (band) { + case BAND_FM: + c = 0; value = 1; + break; + + case BAND_VHF: + if (freq <= 180000) c = 0; + else if (freq <= 188200) c = 1; + else if (freq <= 196400) c = 2; + else c = 3; + value = 1; + break; + + case BAND_LBAND: + if (freq <= 1500000) c = 0; + else if (freq <= 1600000) c = 1; + else c = 3; + break; + + case BAND_SBAND: + c = 7; + dib0070_write_reg(st, 0x1d,0xFFFF); + break; + + case BAND_UHF: + default: + if (st->cfg->flip_chip) { + if (freq <= 550000) c = 0; + else if (freq <= 590000) c = 1; + else if (freq <= 666000) c = 3; + else c = 5; + } else { + if (freq <= 550000) c = 2; + else if (freq <= 650000) c = 3; + else if (freq <= 750000) c = 5; + else if (freq <= 850000) c = 6; + else c = 7; + } + value = 2; + break; + } + + /* default: LNA_MATCH=7, BIAS=3 */ + dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); + dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); + dib0070_write_reg(st, 0x0d, 0x0d80); + + + dib0070_write_reg(st, 0x18, 0x07ff); + dib0070_write_reg(st, 0x17, 0x0033); + + return 0; +} + +static int dib0070_wakeup(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 0); + return 0; +} + +static int dib0070_sleep(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 1); + return 0; +} + +static u16 dib0070_p1f_defaults[] = + +{ + 7, 0x02, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, + + 3, 0x0d, + 0x0d80, + 0x0001, + 0x0000, + + 4, 0x11, + 0x0000, + 0x0103, + 0x0000, + 0x0000, + + 3, 0x16, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, + + 6, 0x1b, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + + 0, +}; + +static void dib0070_wbd_calibration(struct dib0070_state *state) +{ + u16 wbd_offs; + dib0070_write_reg(state, 0x0f, 0x6d81); + dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + msleep(9); + wbd_offs = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, 0); + state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); + dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); +} + +u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + return st->wbd_ff_offset; +} + +EXPORT_SYMBOL(dib0070_wbd_offset); +static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk( "CTRL_LO5: 0x%x", lo5); + return dib0070_write_reg(state, 0x15, lo5); +} + +#define pgm_read_word(w) (*w) +static int dib0070_reset(struct dib0070_state *state) +{ + u16 l, r, *n; + + HARD_RESET(state); + + +#ifndef FORCE_SBAND_TUNER + if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) + state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; + else +#endif + state->revision = DIB0070S_P1A; + + /* P1F or not */ + dprintk( "Revision: %x", state->revision); + + if (state->revision == DIB0070_P1D) { + dprintk( "Error: this driver is not to be used meant for P1D or earlier"); + return -EINVAL; + } + + n = (u16 *) dib0070_p1f_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + if (state->cfg->force_crystal_mode != 0) + r = state->cfg->force_crystal_mode; + else if (state->cfg->clock_khz >= 24000) + r = 1; + else + r = 2; + + r |= state->cfg->osc_buffer_state << 3; + + dib0070_write_reg(state, 0x10, r); + dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); + + if (state->cfg->invert_iq) { + r = dib0070_read_reg(state, 0x02) & 0xffdf; + dib0070_write_reg(state, 0x02, r | (1 << 5)); + } + + + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); + else + dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); + + dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); + return 0; +} + + +static int dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static struct dvb_tuner_ops dib0070_ops = { + .info = { + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune_digital, +// .get_frequency = dib0070_get_frequency, +// .get_bandwidth = dib0070_get_bandwidth +}; + +struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + + if (dib0070_reset(state) != 0) + goto free_mem; + + dib0070_wbd_calibration(state); + + printk(KERN_INFO "DiB0070: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; + +free_mem: + kfree(state); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0070_attach); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h new file mode 100644 index 000000000000..786e37d33889 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.h @@ -0,0 +1,44 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ +#ifndef DIB0070_H +#define DIB0070_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 + +struct dib0070_config { + u8 i2c_address; + + /* tuner pins controlled externally */ + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + u8 osc_buffer_state; /* 0= normal, 1= tri-state */ + u32 clock_khz; + u8 clock_pad_drive; /* (Drive + 1) * 2mA */ + + u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ + + u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ + + u8 flip_chip; +}; + +extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); + +#endif diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index cbbe2c2f05dc..38d2322cbaf6 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -593,7 +593,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 608156a691de..0ad9f3eb20a6 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -42,9 +42,9 @@ struct dib7000m_state { u32 timf_default; u32 internal_clk; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u16 revision; @@ -302,7 +302,7 @@ static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000m_write_word(state, 263 + state->reg_offs, 6); @@ -620,7 +620,7 @@ static int dib7000m_update_lna(struct dib7000m_state *state) u16 dyn_gain; if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000m_read_word(state, 390); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed @@ -754,7 +754,7 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 156c53ab56db..1175ab9a4532 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -36,9 +36,9 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u8 agc_state; @@ -156,7 +156,7 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000p_write_word(state, 204, 6); @@ -294,6 +294,16 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) return 0; } +int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); +} + +EXPORT_SYMBOL(dib7000p_set_wbd_ref); static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -335,6 +345,28 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib7000p_read_word(st, 1029); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib7000p_write_word(st, 1029, st->gpio_dir); + + st->gpio_val = dib7000p_read_word(st, 1030); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib7000p_write_word(st, 1030, st->gpio_val); + + return 0; +} + +int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) +{ + struct dib7000p_state *state = demod->demodulator_priv; + return dib7000p_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib7000p_set_gpio); static u16 dib7000p_defaults[] = { @@ -501,7 +533,7 @@ static int dib7000p_update_lna(struct dib7000p_state *state) // when there is no LNA to program return immediatly if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); @@ -617,7 +649,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index e7769e7cd92a..eefcac8b5244 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -40,12 +40,7 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - -/* TODO -extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); -extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); -extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); -extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod); -*/ +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif From 82f3d5594240adcd8d6764cf31dffc473a6cc1d0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:50:28 -0300 Subject: [PATCH 039/310] V4L/DVB (5956): Add remote control support for the Hauppauge Nova-T 500 This patch adds remote control support for the Hauppauge Nova-T 500 using the same keys as for STK7700PD. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 26 ++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 558ab3bd6889..994e5b8d44a2 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -264,7 +264,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -274,7 +274,7 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("stk7700d:RC Query Failed\n"); + err("RC Query Failed\n"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,14 +287,12 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); } return 0; } -#define KEY_MAP_SIZE (25+48) - -static struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -370,7 +368,7 @@ static struct dvb_usb_rc_key stk7700d_rc_keys[] = { { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, { 0xeb, 0x5c, KEY_NEXT } - }; +}; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { @@ -864,7 +862,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, { NULL }, }, - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -901,10 +904,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, }, + .rc_interval = DEFAULT_RC_INTERVAL, - .rc_key_map = stk7700d_rc_keys, - .rc_key_map_size = KEY_MAP_SIZE, - .rc_query = stk7700d_rc_query + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, From 7161f27f2e61b44352a9dcf3927813380d5e710b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:54:55 -0300 Subject: [PATCH 040/310] V4L/DVB (5957): Add remote keymap for the Hauppauge Nova-TD Stick Copied from drivers/media/dvb/dvb-usb/nova-t-usb2.c Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 51 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 994e5b8d44a2..fb1a9bf7e591 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -346,7 +346,7 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x1a, KEY_BLUE }, { 0xeb, 0x1b, KEY_CHANNELUP }, { 0xeb, 0x1c, KEY_VOLUMEUP }, - { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1d, KEY_MUTE }, { 0xeb, 0x1e, KEY_VOLUMEDOWN }, { 0xeb, 0x1f, KEY_CHANNELDOWN }, { 0xeb, 0x40, KEY_PAUSE }, @@ -367,7 +367,54 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x4f, KEY_FASTFORWARD }, { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, - { 0xeb, 0x5c, KEY_NEXT } + { 0xeb, 0x5c, KEY_NEXT }, + + /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ + { 0x1e, 0x00, KEY_0 }, + { 0x1e, 0x01, KEY_1 }, + { 0x1e, 0x02, KEY_2 }, + { 0x1e, 0x03, KEY_3 }, + { 0x1e, 0x04, KEY_4 }, + { 0x1e, 0x05, KEY_5 }, + { 0x1e, 0x06, KEY_6 }, + { 0x1e, 0x07, KEY_7 }, + { 0x1e, 0x08, KEY_8 }, + { 0x1e, 0x09, KEY_9 }, + { 0x1e, 0x0a, KEY_KPASTERISK }, + { 0x1e, 0x0b, KEY_RED }, + { 0x1e, 0x0c, KEY_RADIO }, + { 0x1e, 0x0d, KEY_MENU }, + { 0x1e, 0x0e, KEY_GRAVE }, /* # */ + { 0x1e, 0x0f, KEY_MUTE }, + { 0x1e, 0x10, KEY_VOLUMEUP }, + { 0x1e, 0x11, KEY_VOLUMEDOWN }, + { 0x1e, 0x12, KEY_CHANNEL }, + { 0x1e, 0x14, KEY_UP }, + { 0x1e, 0x15, KEY_DOWN }, + { 0x1e, 0x16, KEY_LEFT }, + { 0x1e, 0x17, KEY_RIGHT }, + { 0x1e, 0x18, KEY_VIDEO }, + { 0x1e, 0x19, KEY_AUDIO }, + { 0x1e, 0x1a, KEY_MEDIA }, + { 0x1e, 0x1b, KEY_EPG }, + { 0x1e, 0x1c, KEY_TV }, + { 0x1e, 0x1e, KEY_NEXT }, + { 0x1e, 0x1f, KEY_BACK }, + { 0x1e, 0x20, KEY_CHANNELUP }, + { 0x1e, 0x21, KEY_CHANNELDOWN }, + { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */ + { 0x1e, 0x25, KEY_OK }, + { 0x1e, 0x29, KEY_BLUE}, + { 0x1e, 0x2e, KEY_GREEN }, + { 0x1e, 0x30, KEY_PAUSE }, + { 0x1e, 0x32, KEY_REWIND }, + { 0x1e, 0x34, KEY_FASTFORWARD }, + { 0x1e, 0x35, KEY_PLAY }, + { 0x1e, 0x36, KEY_STOP }, + { 0x1e, 0x37, KEY_RECORD }, + { 0x1e, 0x38, KEY_YELLOW }, + { 0x1e, 0x3b, KEY_GOTO }, + { 0x1e, 0x3d, KEY_POWER }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ From 1f8ca4b37355cc56a4d25d5698a894ec46964f83 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 14:24:37 -0300 Subject: [PATCH 041/310] V4L/DVB (5958): Add support Compro VideoMate 500 with DiB7000PC Add support Compro VideoMate 500 with DiB7000PC. Another design of Compro uses the DiB7000PC and it has new USB ids. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 3 ++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index fb1a9bf7e591..b0ae5b731296 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -818,6 +818,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -874,7 +875,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Compro Videomate U500", - { &dib0700_usb_id_table[6], NULL }, + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, { NULL }, }, { "Uniwill STK7700P based (Hama and others)", diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index dae605bbd0f9..a16be605c630 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -59,6 +59,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 +#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 From 8779737b8e01b95fe6f1e33dc90ea621281c7b67 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 17:02:17 -0300 Subject: [PATCH 042/310] V4L/DVB (5959): Fix for size of remote keys in DiB0700 Fix for size of remote control keys in DiB0700. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index b0ae5b731296..a2b2830f978a 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -914,7 +914,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -955,7 +955,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, From 8f6956c7f9fa72c502bde47df4122bd32d0b86d5 Mon Sep 17 00:00:00 2001 From: Matt Doran Date: Tue, 31 Jul 2007 07:09:30 -0300 Subject: [PATCH 043/310] V4L/DVB (5960): Add module parameter to enable SFN workaround In some areas in the world the broadcasters are not using the same cellid for each transmitter in a SFN. The DiBcom has problems with that setup. The module parameter buggy_sfn_workaround makes it re-usable. Signed-off-by: Matt Doran Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 22 +++++++++++++++++----- drivers/media/dvb/frontends/dib7000p.c | 21 +++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 38d2322cbaf6..f0096de2279e 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -13,10 +13,6 @@ #include #include -//#include -//#include -//#include -//#include #include "dvb_frontend.h" @@ -26,6 +22,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { @@ -42,6 +42,8 @@ struct dib3000mc_state { fe_bandwidth_t current_bandwidth; u16 dev_id; + + u8 sfn_workaround_active :1; }; static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) @@ -591,7 +593,14 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame dib3000mc_set_channel_cfg(state, ch, 0); // activates isi - dib3000mc_write_word(state, 29, 0x1073); + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active\n"); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift + } else { + dib3000mc_write_word(state, 29, 0x1073); + dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift + } dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { @@ -679,6 +688,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); msleep(100); diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1175ab9a4532..aa7dc4503323 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -18,6 +18,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { @@ -44,6 +48,8 @@ struct dib7000p_state { u16 gpio_dir; u16 gpio_val; + + u8 sfn_workaround_active :1; }; enum dib7000p_power_mode { @@ -751,8 +757,8 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte /* offset loop parameters */ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 29, 0x1273); // isi dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ @@ -959,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet msleep(45); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); + tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); + if (state->sfn_workaround_active) { + dprintk( "SFN workaround is active"); + tmp |= (1 << 9); + dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + } else { + dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + } + dib7000p_write_word(state, 29, tmp); // never achieved a lock with that bandwidth so far - wait for osc-freq to update if (state->timf == 0) @@ -1119,6 +1133,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); From 3db78e59500a45e05cbe271c8e1ba5a2b7ce0ef8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 08:19:28 -0300 Subject: [PATCH 044/310] V4L/DVB (5961): Fix support for DiB7000M-devices Forgot to initialize the timf_default field. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1 + drivers/media/dvb/frontends/dib7000m.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a2b2830f978a..a70fe75bcb27 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -515,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = { (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k 60258167, // ifreq 20452225, // timf + 30000000, // xtal }; static struct dib7000m_config stk7700p_dib7000m_config = { diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 0ad9f3eb20a6..fb18441a8c57 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1344,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + st->timf_default = cfg->bw->timf; + if (dib7000m_identify(st) != 0) goto error; From 034d65ed209f8525b1989dc3e6beca92fad57a7d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 08:48:40 -0300 Subject: [PATCH 045/310] V4L/DVB (5962): Fix line-break in err output line-breaks in dib0700-remote-query function fixed. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a70fe75bcb27..0eca0fc75327 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -274,7 +274,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("RC Query Failed\n"); + err("RC Query Failed"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,7 +287,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); } return 0; } From 8d99996b0942ff566c62602d83ac2c13521bbe40 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 10:36:06 -0300 Subject: [PATCH 046/310] V4L/DVB (5963): Module parameter description for SFN workaround Thanks to Matt Doran I found that there the module parameter description was not OK. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000p.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index f0096de2279e..edae0be063f5 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aa7dc4503323..f45bcfc51cf8 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -20,7 +20,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) From 89f4267d6fa96cb3db053d5183558c94ad5f46e5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 19:45:13 -0300 Subject: [PATCH 047/310] V4L/DVB (5964): Fixed remote control for dib0700 with new firmware The new firmware returns the data of the REQUEST_POLL_RC request in reversed order. The default is RC5, but it can be adjusted using a module parameter. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 1 + drivers/media/dvb/dvb-usb/dib0700_core.c | 21 ++++++++++++++++++++- drivers/media/dvb/dvb-usb/dib0700_devices.c | 10 +++++----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 74ae6c24087e..4a903ea95896 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -30,6 +30,7 @@ extern int dvb_usb_dib0700_debug; // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_RC 0x11 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 8a1ea114deb0..3ea294eb96bd 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug; module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_dib0700_ir_proto = 1; +module_param(dvb_usb_dib0700_ir_proto, int, 0644); +MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { @@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return dib0700_ctrl_wr(adap->dev, b, 4); } +static int dib0700_rc_setup(struct dvb_usb_device *d) +{ + u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0}; + int i = dib0700_ctrl_wr(d, rc_setup, 3); + if (i<0) { + err("ir protocol setup failed"); + return -1; + } + return 0; +} + static int dib0700_probe(struct usb_interface *intf, const struct usb_device_id *id) { int i; + struct dvb_usb_device *dev; for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0) + { + dib0700_rc_setup(dev); return 0; + } return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0eca0fc75327..4a3c5467d7e0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -275,19 +275,19 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { err("RC Query Failed"); - return 0; + return -1; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; - if (key[1]!=st->rc_toggle) { + if (key[3-1]!=st->rc_toggle) { for (i=0;iprops.rc_key_map_size; i++) { - if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; - st->rc_toggle=key[1]; + st->rc_toggle=key[3-1]; return 0; } } - err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]); } return 0; } From 813ce47cee33964ff710d2c91063548773cb4cd5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 1 Aug 2007 10:13:36 -0300 Subject: [PATCH 048/310] V4L/DVB (5965): Frontend_ioctl(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "fe" was NULL. Since "fe" being NULL seems impossible at this point this patch removes the NULL check. Signed-off-by: Adrian Bunk Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index afe797b75de4..fd9bac5eb25e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -748,7 +748,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, dprintk ("%s\n", __FUNCTION__); - if (!fe || fepriv->exit) + if (fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && From b4b38bd63c07c8927b43c6c378eca1db10fdaf2e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:44:13 -0300 Subject: [PATCH 049/310] V4L/DVB (5970): ivtv: prevent vertical overflow of yuv output When the video standard is changed, there's no guarantee the framebuffer dimensions are still legal. The yuv output code uses these dimensions to calculate the size & position for the video overlay. If the framebuffer dimensions are now illegal, the output may exceed the vertical limit of the display, causing distortion. This patch adds an additional check to ensure the output doesn't exceed the limits for the current video standard, cropping if required. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bcea09542e5a..70ddf4060d37 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -898,8 +898,21 @@ static void ivtv_yuv_init (struct ivtv *itv) itv->yuv_info.decode_height = 480; /* If no visible size set, assume full size */ - if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; - if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + if (!itv->yuv_info.osd_vis_w) + itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; + + if (!itv->yuv_info.osd_vis_h) { + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } else { + /* If output video standard has changed, requested height may + not be legal */ + if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) { + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset, + itv->yuv_info.decode_height); + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } + } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); From 68a341a53ab5a3c5b7dad4b226124414c62c124d Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:51:58 -0300 Subject: [PATCH 050/310] V4L/DVB (5971): ivtv-fb: framebuffer timings no longer locked on module load Framebuffer timings are currently locked to the video format in use when the module is loaded. If the video format is then changed, the timings returned by the framebuffer will be for the original format. This patch ensures that the timings returned reflect the current video format. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 00765da8a6a0..d2cc03172749 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -164,11 +164,6 @@ MODULE_LICENSE("GPL"); #define IVTV_OSD_BPP_32 0x04 struct osd_info { - /* Timing info for modes */ - u32 pixclock; - u32 hlimit; - u32 vlimit; - /* Physical base address */ unsigned long video_pbase; /* Relative base address (relative to start of decoder memory) */ @@ -579,10 +574,25 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { struct osd_info *oi = itv->osd_info; - int osd_height_limit = itv->is_50hz ? 576 : 480; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { @@ -723,8 +733,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = oi->hlimit - var->left_margin - var->xres; - var->lower_margin = oi->vlimit - var->upper_margin - var->yres; + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -733,9 +743,10 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock /= 2; + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, @@ -875,18 +886,6 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) struct v4l2_rect start_window; int max_height; - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - oi->pixclock = 84316; - oi->hlimit = 776; - oi->vlimit = 591; - } - else { - oi->pixclock = 83926; - oi->hlimit = 776; - oi->vlimit = 495; - } - /* Color mode */ if (osd_compat) osd_depth = 32; From 943e8910db31e36d945f2bf7d4c273ca5fa01f6e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:58:29 -0300 Subject: [PATCH 051/310] V4L/DVB (5972): ivtv: prevent yuv register updates from being missed The yuv output code always compares the new frame position & size with those of the previous frame. If they are different, a flag is set to request the yuv output registers be updated when the new frame is displayed. If the incoming frames are delivered too fast, exhausting the buffers, the most recent frame already buffered will be discarded. Unfortunately, any update request will also be discarded. If the new frame matches the size & position of the now discarded frame, the yuv registers are not flagged for update & will remain in their old state. This patch preserves the register update flag in the event that a frame is dropped. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 70ddf4060d37..5c94d3282c82 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -940,6 +940,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) int rc = 0; int got_sig = 0; int frame, next_fill_frame, last_fill_frame; + int register_update = 0; IVTV_DEBUG_INFO("yuv_prep_frame\n"); @@ -953,6 +954,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* Buffers are full - Overwrite the last frame */ next_fill_frame = frame; frame = (frame - 1) & 3; + register_update = itv->yuv_info.new_frame_info[frame].update; } /* Take a snapshot of the yuv coordinate information */ @@ -991,6 +993,8 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } + itv->yuv_info.new_frame_info[frame].update |= register_update; + /* DMA the frame */ mutex_lock(&itv->udma.lock); From bfd7beacff2b5c811badb587a74c3dfbf7f98721 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 10:01:39 -0300 Subject: [PATCH 052/310] V4L/DVB (5973): ivtv: attach yuv field order to each frame In the current driver, the field order is global. As soon as it's changed it takes immediate effect. This is a problem when the video changes order mid stream. Although it mostly works okay, the video may judder / flicker. This patch attaches the field order to the frame, so that any buffered frames will not be displayed until the correct field. In the event that the field order is changed mid stream, the driver will ensure that the previous frame is displayed for a minimum of 3 fields. These are the two original fields the frame should have occupied, plus the one extra since the new frame still has to wait for the correct field. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 7 ++++++- drivers/media/video/ivtv/ivtv-irq.c | 22 ++++++++++++++-------- drivers/media/video/ivtv/ivtv-yuv.c | 12 +++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6e53a1f04f7e..6c7c9a57a1ab 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -531,6 +531,7 @@ struct yuv_frame_info u32 tru_w; u32 tru_h; u32 offset_y; + int lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -603,7 +604,6 @@ struct yuv_playback_info int decode_height; int frame_interlaced; - int frame_interlaced_last; int lace_mode; int lace_threshold; @@ -614,6 +614,11 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; + + int sync_field[4]; /* Field to sync on */ + int field_delay[4]; /* Flag to extend duration of previous frame */ + u8 fields_lapsed; /* Counter used when delaying a frame */ + struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fcd6e7f5f121..88c6f4ff5c6d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -698,17 +698,21 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || + if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && + ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + next_dma_frame = (next_dma_frame + 1) & 0x3; + atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + itv->yuv_info.fields_lapsed = -1; + } } } if (frame != (itv->lastVsyncFrame & 1)) { @@ -749,6 +753,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } + + itv->yuv_info.fields_lapsed ++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 5c94d3282c82..fa8c76f3d359 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -612,7 +612,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi itv->yuv_info.v_filter_2 = v_filter_2; } - itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; } /* Modify the supplied coordinate information to fit the visible osd area */ @@ -799,6 +798,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo (itv->yuv_info.old_frame_info.src_y != window->src_y) || (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || + (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; @@ -970,6 +970,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + /* Snapshot field order */ + itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) itv->yuv_info.new_frame_info[frame].offset_y = 1; @@ -985,6 +988,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update = 0; itv->yuv_info.new_frame_info[frame].interlaced_y = 0; itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; + itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.new_frame_info[frame]))) { @@ -995,6 +999,12 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update |= register_update; + /* Should this frame be delayed ? */ + if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) + itv->yuv_info.field_delay[frame] = 1; + else + itv->yuv_info.field_delay[frame] = 0; + /* DMA the frame */ mutex_lock(&itv->udma.lock); From 19dc74b7c5f02ada19840a85582f42f4dddcdb3e Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 23:06:50 -0300 Subject: [PATCH 053/310] V4L/DVB (5975): cx88: Wrong values used for HD-3000 radio mode After some tedious work with a logic probe and a magnifying glass, I've determined that GPIO 7 is used to switch between the DTT7612's Sound 4.5 MHz IF output on pin 12 and the FM 10.7MHz If output on pin 11. GPIO 2 is used to switch the card's analog sound output from from the analog input connector to the CX23883's audio DACs. So, in radio mode GPIO2 = 1 and GPIO7 = 0. Add some comments about how the HD-3000's GPIOs are connected. Delete the vmux setting for the radio, as vmux doesn't apply to radio mode. Also delete the lines setting unused gpio words to zero; it's not necessary as 0 is the default value for uninitialized fields. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6a136ddbccf8..1fc71a78b926 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -575,35 +575,34 @@ struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + /* GPIO[2] = audio source for analog audio out connector + * 0 = analog audio input connector + * 1 = CX88 audio DACs + * + * GPIO[7] = input to CX88's audio/chroma ADC + * 0 = FM 10.7 MHz IF + * 1 = Sound 4.5 MHz IF + * + * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively + * + * GPIO[16] = Remote control input + */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, }}, .radio = { .type = CX88_RADIO, - .vmux = 2, - .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, + .gpio0 = 0x00008404, }, .mpeg = CX88_MPEG_DVB, }, From b97762ba18b57c7057b58ed4f7140a19d0166b01 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 18:51:30 -0300 Subject: [PATCH 054/310] V4L/DVB (5976): mt2131 s5h1409: correct frontend selection logic If a card driver is compiled into the kernel and mt2131 or s5h1409 are compiled as modules, the kernel won't link. A compiled in driver can't use a module, so in this case the mt2131 or s5h1409 are effectively disabled w.r.t the compiled in driver and the stub attach function should be used. Signed-off-by: Trent Piepho Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.h | 2 +- drivers/media/dvb/frontends/s5h1409.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 608f1f66c9e7..1e4ffe7dc8c8 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index bccfd8a6fbd4..20f9af1af445 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -53,7 +53,7 @@ struct s5h1409_config u8 status_mode; }; -#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else From a75d204860b5051ebd5635278c097bafb4ea53f9 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 1 Aug 2007 00:13:28 -0300 Subject: [PATCH 055/310] V4L/DVB (5977): cx8800: Add register debug functions to radio device too Add the advanced debug functions to the radio videodev template. One could already use them from the video and vbi devices. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 41b5cb63fd2d..58ec76be436c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1716,6 +1716,10 @@ static struct video_device cx8800_radio_template = .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif }; /* ----------------------------------------------------------- */ From 5e082f1521598a91c9194b2356b157cade9b6e87 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 3 Aug 2007 18:32:38 -0300 Subject: [PATCH 056/310] V4L/DVB (5978): tuner: Better tuner radio support Add radio support for the Thomson DTT7612 tuner. This tuner uses a different 1st intermediate frequency than the other radio tuners supported (a lot of NTSC radio tuners probably need this change too). Add a new tuner-simple parameter, radio_if. It selects the 1st IF used for radio reception. The radio frequency setting code in tuner-simple now uses this field, instead of a special case select() block for each tuner with radio support. The tuner parameters for tuners that used a 33.3 MHz RIF now set radio_if to 1 in tuner-types.c. The Thomson DTT7612 gets radio_if = 2, also add has_tda9887 = 1 and fm_gain_normal = 1. Add some defines for tda9887 bits that control IF setting in radio mode. Add a new tda9887 config option, TDA9887_RIF_41_3, that selects a 41.3 MHz radio IF. Fix the way tda9887 radio options work. The driver was modifying the default radio mode config templates based on the TDA9887_XXXX flags. This means that _all_ tuners would get the same settings. If you had a one tuner than used TDA9887_GAIN_NORMAL and one that didn't, both would get the setting. Now the tda9987 driver just checks if tuner mode is radio and then applies the config settings directly to the data being sent, just like how all the TV mode settings already work. The PLL setting math is made a little more accurate. And a grammar error in a printk is fixed. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 19 ++++++++-- drivers/media/video/tuner-simple.c | 57 +++++++++++++++++++----------- drivers/media/video/tuner-types.c | 5 +++ include/media/tuner-types.h | 4 +++ include/media/tuner.h | 1 + 5 files changed, 63 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index a8f773274fe3..aa311e4f1f61 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -97,6 +97,8 @@ struct tvnorm { #define cAudioIF_6_5 0x03 // bit e0:1 +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ #define cVideoIF_58_75 0x00 // bit e2:4 #define cVideoIF_45_75 0x04 // bit e2:4 #define cVideoIF_38_90 0x08 // bit e2:4 @@ -106,6 +108,13 @@ struct tvnorm { #define cRadioIF_45_75 0x18 // bit e2:4 #define cRadioIF_38_90 0x1C // bit e2:4 +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 #define cTunerGainNormal 0x00 // bit e5 #define cTunerGainLow 0x20 // bit e5 @@ -487,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf) if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->tda9887_config & TDA9887_GAIN_NORMAL) { - radio_stereo.e &= ~cTunerGainLow; - radio_mono.e &= ~cTunerGainLow; + if (t->mode == V4L2_TUNER_RADIO) { + if (t->tda9887_config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (t->tda9887_config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; } return 0; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2d57e8bc0db3..10a7d36a2646 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -402,53 +402,68 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) u8 buffer[4]; u16 div; int rc, j; - enum param_type desired_type = TUNER_PARAM_TYPE_RADIO; struct tuner_params *params; tun = &tuners[t->type]; - for (j = 0; j < tun->count-1; j++) { - if (desired_type != tun->params[j].type) - continue; - break; - } - /* use default tuner_params if desired_type not available */ - if (desired_type != tun->params[j].type) - j = 0; - - div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default params (j=0) will be used if desired type wasn't found */ params = &tun->params[j]; - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + /* Select Radio 1st IF used */ + switch (params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); + break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", params->radio_if); + return; + } + + /* Bandswitch byte */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: buffer[3] = 0x11; break; - case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0x19; - break; case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; - case TUNER_MICROTUNE_4049FM5: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0xa4; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; break; + case TUNER_MICROTUNE_4049FM5: default: buffer[3] = 0xa4; break; } + + buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + if (params->cb_first_if_lower_freq && div < t->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; @@ -475,6 +490,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config &= ~TDA9887_PORT1_ACTIVE;*/ if (params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; + if (params->radio_if == 2) + config |= TDA9887_RIF_41_3; i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); } if (4 != (rc = i2c_master_send(c,buffer,4))) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 53a99b39387f..c6a7934bd5a6 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .port1_invert_for_secam_lc = 1, .default_pll_gating_18 = 1, .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -733,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_fm1236_mk3_ntsc_ranges, .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -859,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt761x_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ }, }; diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h index e5ad3fcfe984..b201371416a0 100644 --- a/include/media/tuner-types.h +++ b/include/media/tuner-types.h @@ -79,6 +79,10 @@ struct tuner_params { /* Select 18% (or according to datasheet 0%) L standard PLL gating, vs the driver default of 36%. */ unsigned int default_pll_gating_18:1; + /* IF to use in radio mode. Tuners with a separate radio IF filter + seem to use 10.7, while those without use 33.3 for PAL/SECAM tuners + and 41.3 for NTSC tuners. 0 = 10.7, 1 = 33.3, 2 = 41.3 */ + unsigned int radio_if:2; /* Default tda9887 TOP value in dB for the low band. Default is 0. Range: -16:+15 */ signed int default_top_low:5; diff --git a/include/media/tuner.h b/include/media/tuner.h index 160381c72e4b..c03dceb92605 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -146,6 +146,7 @@ extern int tuner_debug; #define TDA9887_AUTOMUTE (1<<18) #define TDA9887_GATING_18 (1<<19) #define TDA9887_GAIN_NORMAL (1<<20) +#define TDA9887_RIF_41_3 (1<<21) /* radio IF1 41.3 vs 33.3 */ #ifdef __KERNEL__ From 4f76b672c4f9ceb9e7e0aa6224293da0ae7430da Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 6 Aug 2007 13:59:19 -0300 Subject: [PATCH 057/310] V4L/DVB (5980): tda8083: fix frequency and symbolrate info The TDA8083 supports a symbol rate from 12..30 MSym/s. The Grundig 29504-451 tuner uses the TDA8060 down-converter, which has a frequency range from 920..2200MHz. Thanks-to: Lars Buerding Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda8083.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 67415c9db6f7..0f041e873781 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -443,12 +443,12 @@ static struct dvb_frontend_ops tda8083_ops = { .info = { .name = "Philips TDA8083 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, /* FIXME: guessed! */ - .frequency_max = 1400000, /* FIXME: guessed! */ + .frequency_min = 920000, /* TDA8060 */ + .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ /* .frequency_tolerance = ???,*/ - .symbol_rate_min = 1000000, /* FIXME: guessed! */ - .symbol_rate_max = 45000000, /* FIXME: guessed! */ + .symbol_rate_min = 12000000, + .symbol_rate_max = 30000000, /* .symbol_rate_tolerance = ???,*/ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | From 5e76a1cb2ce0918ff2429fcfa2d5655dbd273c54 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:27 -0300 Subject: [PATCH 058/310] V4L/DVB (5981): Zoran_driver.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 4dbe2d449b50..d831ca16d9e9 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -3196,7 +3196,7 @@ zoran_do_ioctl (struct inode *inode, "%s: VIDIOC_QUERYBUF - index=%d, type=%d\n", ZR_DEVNAME(zr), buf->index, buf->type); - memset(buf, 0, sizeof(buf)); + memset(buf, 0, sizeof(*buf)); buf->type = type; buf->index = index; From 473c653fff8dc6a63cad279a8e83395ead12119d Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:35 -0300 Subject: [PATCH 059/310] V4L/DVB (5982): Dev.c: memset fix Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index b876aca69c73..0334b9aaf12a 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -448,7 +448,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (cmd == VIDIOCGMBUF) { struct video_mbuf *p=arg; - memset(p,0,sizeof(p)); + memset(p, 0, sizeof(*p)); if (!vfd->vidiocgmbuf) return ret; From 8509a29ec6050a03d88f2da59fc2e361f6c16534 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:45 -0300 Subject: [PATCH 060/310] V4L/DVB (5983): Arv.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 2666d3b76630..19e9929ffa0f 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -441,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, { struct video_window *w = arg; DEBUG(1, "VIDIOCGWIN:\n"); - memset(w, 0, sizeof(w)); + memset(w, 0, sizeof(*w)); w->width = ar->width; w->height = ar->height; return 0; From a18255bef2a62632ed442fdb90b091193cbabca5 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Thu, 9 Aug 2007 00:01:51 -0300 Subject: [PATCH 061/310] V4L/DVB (5985): Fix the min/max frequencies of some DVB-C frontends The min frequencies of the DVB-C frontends are wrong. In Europe, the center frequency of the lowest channel is 50.5MHz and not 51MHz. All known cards with the stv0297/tda0002x/ves1820 frontend are able to tune to this frequency. I've changed the range to the lowest channel - 1/2 bandwidth and the highest channel + 1/2 bandwidth. For the design of the dvb driver, the frequency ranges must be part of the tuner and not of the frontend itself. The same frontend may be used for different tuners. The attached patch does only fix the ranges and not the design. Signed-off-by: Hartmut Birr Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0297.c | 4 ++-- drivers/media/dvb/frontends/tda10021.c | 4 ++-- drivers/media/dvb/frontends/tda10023.c | 4 ++-- drivers/media/dvb/frontends/ves1820.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 9a343972ff50..17e5cb561cd8 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = { .info = { .name = "ST STV0297 DVB-C", .type = FE_QAM, - .frequency_min = 64000000, - .frequency_max = 1300000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .frequency_stepsize = 62500, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index e725f612a6b7..4cd9e82c4669 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = { .name = "Philips TDA10021 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ #if 0 diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index a00cf0f54efc..364bc01971a0 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -500,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ .caps = 0x400 | //FE_CAN_QAM_4 diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 9b57576bfeb4..066b73b75698 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = { .name = "VLSI VES1820 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | From c471b331dda9fdfaf67832998d0b2c848777ab4a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 01:03:42 -0300 Subject: [PATCH 062/310] V4L/DVB (5986): dvb_frontend: Fixed GET_INFO ioctl and check of frequency limits The calculation of frequency limits ignored tuner-specific frequency limits. Range checks and GET_INFO ioctl updated accordingly. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 31 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index fd9bac5eb25e..1a1b2405b0f4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,17 +697,35 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe, + u32 *freq_min, u32 *freq_max) +{ + *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + + if (fe->ops.info.frequency_max == 0) + *freq_max = fe->ops.tuner_ops.info.frequency_max; + else if (fe->ops.tuner_ops.info.frequency_max == 0) + *freq_max = fe->ops.info.frequency_max; + else + *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + + if (*freq_min == 0 || *freq_max == 0) + printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num); +} + static int dvb_frontend_check_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *parms) { + u32 freq_min; + u32 freq_max; + /* range check: frequency */ - if ((fe->ops.info.frequency_min && - parms->frequency < fe->ops.info.frequency_min) || - (fe->ops.info.frequency_max && - parms->frequency > fe->ops.info.frequency_max)) { + dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max); + if ((freq_min && parms->frequency < freq_min) || + (freq_max && parms->frequency > freq_max)) { printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", - fe->dvb->num, parms->frequency, - fe->ops.info.frequency_min, fe->ops.info.frequency_max); + fe->dvb->num, parms->frequency, freq_min, freq_max); return -EINVAL; } @@ -763,6 +781,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_GET_INFO: { struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); + dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ From 276e49a01a7e6c4a7bfb78618cf2f5befbf9f5de Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 02:41:16 -0300 Subject: [PATCH 063/310] V4L/DVB (5987): saa7146: clean-up irq processing Interrupt processing fixed: First handle interrupt, then acknowledge it. Otherwise the same interrupt might occur twice. Cleaned-up i2c interrupt handler and i2c error messages. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 31 ++++++++++++----------------- drivers/media/common/saa7146_i2c.c | 19 ++++++++++++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 12cda9eebd12..1c962a2b44df 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -248,10 +248,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; - u32 isr = 0; + u32 isr; + u32 ack_isr; /* read out the interrupt status register */ - isr = saa7146_read(dev, ISR); + ack_isr = isr = saa7146_read(dev, ISR); /* is this our interrupt? */ if ( 0 == isr ) { @@ -259,8 +260,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) return IRQ_NONE; } - saa7146_write(dev, ISR, isr); - if( 0 != (dev->ext)) { if( 0 != (dev->ext->irq_mask & isr )) { if( 0 != dev->ext->irq_func ) { @@ -283,21 +282,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { - u32 status = saa7146_read(dev, I2C_STATUS); - if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { - SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); - /* only wake up if we expect something */ - if( 0 != dev->i2c_op ) { - u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2; - u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f; - DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr)); - dev->i2c_op = 0; - wake_up(&dev->i2c_wq); - } else { - DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); - } + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); + /* only wake up if we expect something */ + if (0 != dev->i2c_op) { + dev->i2c_op = 0; + wake_up(&dev->i2c_wq); } else { - DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); + u32 psr = saa7146_read(dev, PSR); + u32 ssr = saa7146_read(dev, SSR); + printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", + dev->name, isr, psr, ssr); } isr &= ~(MASK_16|MASK_17); } @@ -306,6 +300,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) ERR(("disabling interrupt source(s)!\n")); SAA7146_IER_DISABLE(dev,isr); } + saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; } diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index f823286341eb..7e7689afae62 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* a signal arrived */ return -ERESTARTSYS; - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n"); + printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } status = saa7146_read(dev, I2C_STATUS); @@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d break; } if (time_after(jiffies,timeout)) { - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n"); + printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", + dev->name, __FUNCTION__); return -EIO; } } @@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* this is normal when probing the bus * (no answer from nonexisistant device...) */ - DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n")); + printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } if (++trial < 50 && short_delay) @@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d } /* give a detailed status report */ - if ( 0 != (status & SAA7146_I2C_ERR)) { + if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | + SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | + SAA7146_I2C_AL | SAA7146_I2C_ERR | + SAA7146_I2C_BUSY)) ) { + if ( 0 == (status & SAA7146_I2C_ERR) || + 0 == (status & SAA7146_I2C_BUSY) ) { + /* it may take some time until ERR goes high - ignore */ + DEB_I2C(("unexpected i2c status %04x\n", status)); + } if( 0 != (status & SAA7146_I2C_SPERR) ) { DEB_I2C(("error due to invalid start/stop condition.\n")); } From 4ebcb48da1eace49ef5f2d83a91984085c6d702d Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 9 Aug 2007 11:29:33 -0300 Subject: [PATCH 064/310] V4L/DVB (5988): Fix OOP on videobuf-dvb when hibernating Since videobuf_waiton is called with intr=1, it can return -EINTR and therefore err may be non-zero. This happens when the system goes into the standby state. Without the BUG() occurring, there's no problem with standby mode while DVB is being used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/video-buf-dvb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index e617925ba31e..d2af82dc8faf 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -56,7 +56,6 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer, stream); list_del(&buf->stream); err = videobuf_waiton(buf,0,1); - BUG_ON(0 != err); /* no more feeds left or stop_feed() asked us to quit */ if (0 == dvb->nfeeds) From 7963fa48dafd07a8c6b6007fb038095553ad6a0f Mon Sep 17 00:00:00 2001 From: Steven Walter Date: Thu, 9 Aug 2007 11:36:35 -0300 Subject: [PATCH 065/310] V4L/DVB (5989): V4L: Add additional ioctls to compat_ioctl32 With the addition of these ioctls, I'm able to watch TV with a 32-bit version of tvtime on x86_64. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index f065ad12cc61..cefd1381e8de 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -848,6 +848,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCSFREQ32: case VIDIOCGAUDIO: case VIDIOCSAUDIO: + case VIDIOCGVBIFMT: + case VIDIOCSVBIFMT: #endif case VIDIOC_QUERYCAP: case VIDIOC_ENUM_FMT: @@ -874,7 +876,10 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_ENUMINPUT: case VIDIOC_ENUMINPUT32: case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_S_CTRL32: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_FREQUENCY: case VIDIOC_QUERYCTRL: case VIDIOC_G_INPUT32: case VIDIOC_S_INPUT32: From 1597f1f676d2c425028b6a20f21a987f489dbdd2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 9 Aug 2007 12:02:30 -0300 Subject: [PATCH 066/310] V4L/DVB (5990): cinergyt2_suspend: don't forget to unlock cinergyt2->wq_sem Restore unlock of cinergyt2->wq_sem, was deleted by accident. Signed-off-by: Oleg Nesterov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 28929b618e20..b910fa0baa07 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -1008,6 +1008,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) cinergyt2_sleep(cinergyt2, 1); mutex_unlock(&cinergyt2->sem); + mutex_unlock(&cinergyt2->wq_sem); + return 0; } From 94104aa2a88ac2433f7cbde3dbec629263724271 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 04:56:00 -0300 Subject: [PATCH 067/310] V4L/DVB (5992): ivtv: show card name as well in the LOG_STATUS output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index dfe0aedc60fd..85e6a34d5e90 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1209,6 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void int i; IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); if (itv->hw_flags & IVTV_HW_TVEEPROM) { struct tveeprom tv; @@ -1242,7 +1243,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Version: %s Status flags: 0x%08lx\n", IVTV_VERSION, itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; From 89fc4eb924fc8da769083e1680e24c182589d789 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:00:07 -0300 Subject: [PATCH 068/310] V4L/DVB (5993): cx25840: resetting also requires reloading the firmware Resetting without reloading the firmware is not enough. Sometimes the firmware is 'stuck' and needs to be reloaded. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9c12bd39cfb5..9f99007d389b 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,7 +179,7 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } -static void cx25840_initialize(struct i2c_client *client, int loadfw) +static void cx25840_initialize(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); @@ -197,8 +197,7 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - if (loadfw) - cx25840_loadfw(client); + cx25840_loadfw(client); /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -638,7 +637,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 1); + cx25840_initialize(client); } switch (cmd) { @@ -841,7 +840,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 0); + cx25840_initialize(client); break; case VIDIOC_G_CHIP_IDENT: From 2cc720957a743ef59f9925ecfef5f71f08387d8b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:06:23 -0300 Subject: [PATCH 069/310] V4L/DVB (5994): ivtv: make VIDIOC_INT_RESET support smarter. Add support to optionally reset the IR and/or the video digitizer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 85e6a34d5e90..cee6c558c69c 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -681,9 +681,17 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) break; } - case VIDIOC_INT_RESET: - ivtv_reset_ir_gpio(itv); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) { + ivtv_reset_ir_gpio(itv); + } + if (val & 0x02) { + itv->video_dec_func(itv, cmd, 0); + } break; + } default: return -EINVAL; From 372978055dd564d97ca1b4099c99296eaff1fe19 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Sep 2007 11:59:15 -0300 Subject: [PATCH 070/310] V4L/DVB (5995): ivtv: add AverMedia M116 - Split Club3D card from Yuan PG600-2, GotView PCI DVD Lite (different composite input) - Add AVerTV MCE 116 Plus (M116) card - Allow Xceive cards to be used without Xceive support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 81 +++++++++++++++++++++----- drivers/media/video/ivtv/ivtv-driver.c | 27 ++++----- drivers/media/video/ivtv/ivtv-driver.h | 14 ++--- drivers/media/video/ivtv/ivtv-gpio.c | 24 -------- drivers/media/video/ivtv/ivtv-gpio.h | 2 +- 5 files changed, 86 insertions(+), 62 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e51d7cc35b1c..b6a8be622d3c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -823,9 +823,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { /* ------------------------------------------------------------------------- */ -#ifdef HAVE_XC3028 - -/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ +/* Yuan PG600-2/GotView PCI DVD Lite cards */ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, @@ -835,30 +833,87 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, - .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", + .name = "Yuan PG600-2, GotView PCI DVD Lite", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, }, .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .pci_list = ivtv_pci_pg600v2, }; -#endif + +/* ------------------------------------------------------------------------- */ + +/* Club3D ZAP-TV1x01 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_club3d[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_club3d = { + .type = IVTV_CARD_CLUB3D, + .name = "Club3D ZAP-TV1x01", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_club3d, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerTV MCE 116 Plus (M116) card */ + +static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avertv_mce116 = { + .type = IVTV_CARD_AVERTV_MCE116, + .name = "AVerTV MCE 116 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_avertv_mce116, +}; static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, @@ -879,9 +934,9 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_gotview_pci_dvd2, &ivtv_card_yuan_mpc622, &ivtv_card_dctmvtvp1, -#ifdef HAVE_XC3028 &ivtv_card_pg600v2, -#endif + &ivtv_card_club3d, + &ivtv_card_avertv_mce116, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index f8ef267e56b2..198e443e8a5e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -177,9 +177,9 @@ MODULE_PARM_DESC(cardtype, "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" "\t\t\t17 = Yuan MPC622\n" "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" -#ifdef HAVE_XC3028 - "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" -#endif + "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" + "\t\t\t20 = Club3D ZAP-TV1x01\n" + "\t\t\t21 = AverTV MCE 116 Plus\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -821,11 +821,13 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* load modules */ #ifndef CONFIG_VIDEO_TUNER if (hw & IVTV_HW_TUNER) { - ivtv_request_module(itv, "tuner"); -#ifdef HAVE_XC3028 - if (itv->options.tuner == TUNER_XCEIVE_XC3028) - ivtv_request_module(itv, "xc3028-tuner"); -#endif + if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); + itv->tunerid = 1; + } + else { + ivtv_request_module(itv, "tuner"); + } } #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1130,19 +1132,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1) { + if (itv->options.tuner > -1 && itv->tunerid == 0) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ -#ifdef HAVE_XC3028 - setup.initmode = V4L2_TUNER_ANALOG_TV; - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { - setup.gpio_write = ivtv_reset_tuner_gpio; - setup.gpio_priv = itv; - } -#endif ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6c7c9a57a1ab..4a7b23b9f22a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -63,10 +63,9 @@ #include #include -/* #define HAVE_XC3028 1 */ - #include + #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ @@ -114,12 +113,10 @@ extern const u32 yuv_offset[4]; #define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ #define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ #define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#ifdef HAVE_XC3028 -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ -#define IVTV_CARD_LAST 18 -#else -#define IVTV_CARD_LAST 17 -#endif +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -705,6 +702,7 @@ struct ivtv { u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ + int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ /* controlling Video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 6a5a7aa66976..132fb5f71366 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -122,30 +122,6 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } -#ifdef HAVE_XC3028 -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) -{ - int curdir, curout; - struct ivtv *itv = (struct ivtv *) priv; - - if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) - return -EINVAL; - IVTV_INFO("Resetting tuner\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - curout |= (1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - return 0; -} -#endif void ivtv_gpio_init(struct ivtv *itv) { diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index c301d2a39346..b31c679bbd8e 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -21,5 +21,5 @@ /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); +int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); From 87410dab1238623e082e9a78a62f1bbeb6c475e3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:00:36 -0300 Subject: [PATCH 071/310] V4L/DVB (5997): cx25840: fix audio mute handling and reporting Audio muting for the tuner input was implemented by stopping the audio microcontroller and restarting it on unmute. However, it appears that this method can actually crash the audio firmware. It's rare and seems to happen with NTSC only. It has been reimplemented by setting to volume to 0. In addition, the reporting of the mute state has been improved as well: it used to be impossible to detect whether the audio was muted by the user or if it was muted due to the microcontroller trying to detect the audio standard. This is now clearly stated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 53 +++++++++++++-------- drivers/media/video/cx25840/cx25840-core.c | 6 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f897c1ebd5f3..f93b5160bb4f 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -194,19 +194,34 @@ void cx25840_audio_set_path(struct i2c_client *client) static int get_volume(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) + return state->unmute_volume; + /* Volume runs +18dB to -96dB in 1/2dB steps * change to fit the msp3400 -114dB to +12dB range */ /* check PATH1_VOLUME */ - int vol = 228 - cx25840_read(client, 0x8d4); + vol = 228 - cx25840_read(client, 0x8d4); vol = (vol / 2) + 23; return vol << 9; } static void set_volume(struct i2c_client *client, int volume) { - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) { + state->unmute_volume = volume; + return; + } + + /* Convert the volume to msp3400 values (0-127) */ + vol = volume >> 9; + /* now scale it up to cx25840 values * -114dB to -96dB maps to 0 * this should be 19, but in my testing that was 4dB too loud */ @@ -284,30 +299,26 @@ static void set_balance(struct i2c_client *client, int balance) static int get_mute(struct i2c_client *client) { - /* check SRC1_MUTE_EN */ - return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; + struct cx25840_state *state = i2c_get_clientdata(client); + + return state->unmute_volume >= 0; } static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); - if (state->aud_input != CX25840_AUDIO_SERIAL) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - if (mute) { - /* disable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_write(client, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } - } else { - /* SRC1_MUTE_EN */ - cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + if (mute && state->unmute_volume == -1) { + int vol = get_volume(client); + + set_volume(client, 0); + state->unmute_volume = vol; + } + else if (!mute && state->unmute_volume != -1) { + int vol = state->unmute_volume; + + state->unmute_volume = -1; + set_volume(client, vol); } } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9f99007d389b..65ad7943dd9a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -915,6 +915,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; + state->unmute_volume = -1; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; @@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client) } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); + (state->unmute_volume >= 0) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { case 0x00: p = "undefined"; break; diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8c1fbd9b87c1..86e2edfc4941 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -42,6 +42,7 @@ struct cx25840_state { enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; + int unmute_volume; /* -1 if not muted */ int vbi_line_offset; u32 id; u32 rev; From 9085009683dd46d95105eda14efa8bda403b459f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:02:45 -0300 Subject: [PATCH 072/310] V4L/DVB (5998): ivtv: no need to mute the audio input When changing channels the audio has to be muted. This is done by calling CX2341X_ENC_MUTE_AUDIO and by muted the audio input. The latter is not necessary and is now removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index fedddecf661e..9e867b5229d1 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -924,21 +924,13 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) void ivtv_mute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; - - /* Mute sound to avoid pop */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); - if (atomic_read(&itv->capturing)) ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); - IVTV_DEBUG_INFO("Mute\n"); } void ivtv_unmute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; - /* initialize or refresh input */ if (atomic_read(&itv->capturing) == 0) ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); @@ -949,8 +941,5 @@ void ivtv_unmute(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } - - /* Unmute */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); IVTV_DEBUG_INFO("Unmute\n"); } From 39c4ad6ab364354bf76cdcc0081fa5c4422db907 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 14:24:17 -0300 Subject: [PATCH 073/310] V4L/DVB (5999): cx25840: add radio support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 65ad7943dd9a..8f9c32613b45 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -251,7 +251,11 @@ static void input_change(struct i2c_client *client) cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); - if (std & V4L2_STD_525_60) { + if (state->radio) { + cx25840_write(client, 0x808, 0xf9); + cx25840_write(client, 0x80b, 0x00); + } + else if (std & V4L2_STD_525_60) { /* Certain Hauppauge PVR150 models have a hardware bug that causes audio to drop out. For these models the audio standard must be set explicitly. From 6af5a0394ae9ce7ac8eea233a8c430d743a377c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:19:33 -0300 Subject: [PATCH 074/310] V4L/DVB (6002): ivtv: remove unused struct field. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 4a7b23b9f22a..0a1c16ad10bb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -651,7 +651,6 @@ struct vbi_info { struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; - u32 service_set_in; int insert_mpeg; /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. From be848fe39a656fd57429263f5ac8c656ccdff362 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2007 17:13:22 -0300 Subject: [PATCH 075/310] V4L/DVB (6003): vp27smpx: correctly attribute the origin of the driver Correctly attribute the origin of the driver to Kazuhiko Kawakami. It took some time to get the S-O-B line from the original tvaudio patch author, but here it is. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 9aa526bd2c84..8a81fcd13ae9 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007 Hans Verkuil * - * Special thanks to Kazz for the i2c data. + * Based on a tvaudio patch from Kazuhiko Kawakami * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From afa76b392e10d37c9e717198b5c2686de26c629d Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 13 Aug 2007 08:08:21 -0300 Subject: [PATCH 076/310] V4L/DVB (6005): Initialize filp->private_data only once in em28xx_v4l2_open Some lines later filp->private_data is initialized to dev again. Since there are some checks that might fail in the mean time keep the later version. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 40307f3f6fe3..e4fba9068336 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -268,8 +268,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) if (NULL == dev) return -ENODEV; - filp->private_data=dev; - em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); From 6b1dde90de7f612805fbe8212a39264d7b868efc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 11 Aug 2007 15:42:12 -0300 Subject: [PATCH 077/310] V4L/DVB (6006): tuner: move last_div to tuner-simple private data tuner-simple is the only sub-driver that uses last_div, so we can free up two bytes of memory for all other tuners, by moving this into tuner-simple's private data area. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 1 - drivers/media/video/tuner-simple.c | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 0334a9125077..fa51b7cec691 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -49,7 +49,6 @@ struct tuner { unsigned int tv_freq; /* keep track of the current settings */ unsigned int radio_freq; - u16 last_div; unsigned int audmode; v4l2_std_id std; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 10a7d36a2646..572f22423b98 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -82,6 +82,10 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 +struct tuner_simple_priv { + u16 last_div; +}; + /* ---------------------------------------------------------------------- */ static int tuner_getstatus(struct i2c_client *c) @@ -126,6 +130,7 @@ static int tuner_stereo(struct i2c_client *c) static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; @@ -291,7 +296,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -302,7 +307,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[2] = config; buffer[3] = cb; } - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && @@ -399,6 +404,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tunertype *tun; struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; int rc, j; @@ -464,7 +470,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -476,7 +482,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; @@ -498,16 +504,31 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } +static void tuner_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations simple_tuner_ops = { .set_tv_freq = default_set_tv_freq, .set_radio_freq = default_set_radio_freq, .has_signal = tuner_signal, .is_stereo = tuner_stereo, + .release = tuner_release, }; int default_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); From fbd8af07063f7379e71654013e7915315cd869f8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 15 Aug 2007 10:43:08 -0300 Subject: [PATCH 078/310] V4L/DVB (6009): Bt8xx: "extern inline" -> "static inline" "extern inline" will have different semantics with gcc 4.3. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index f685bc129609..1c8e3366000f 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -149,7 +149,7 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), "r"(addr)); From e9f668dd12d3ed293af0d466bcaa393b78a7d0ee Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 15 Aug 2007 10:43:19 -0300 Subject: [PATCH 079/310] V4L/DVB (6010): Use inline functions instead of inline asm for powerpc Change io_st_le32() to use inline functions rather than direct inline assembly code. Signed-off-by: Kumar Gala Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 1c8e3366000f..d593bc145628 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -151,9 +151,8 @@ void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { - __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), - "r"(addr)); - __asm__ __volatile__("eieio":::"memory"); + st_le32(addr, val); + eieio(); } #define bmtwrite(dat,adr) io_st_le32((adr),(dat)) From acb09af4e333dc92cdd32ae75ee7e5f3d7aaf60b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 29 Jul 2007 22:56:11 -0300 Subject: [PATCH 080/310] V4L/DVB (6014): vivi: use videobuf_read_stream() videobuf_read_stream is more efficient than videobuf_read_one Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index f6d3a9460ccc..c10169e35753 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1123,7 +1123,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (res_locked(fh->dev)) return -EBUSY; - return videobuf_read_one(&fh->vb_vidq, data, count, ppos, + return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } return 0; From 5f553388b06532b495681f5d6c8e8fbff64ea86a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 14:00:09 -0300 Subject: [PATCH 081/310] V4L/DVB (6015): DVB: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a trivial patch that converts DVB to use struct device. Signed-off-by: Kay Sievers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvbdev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 9ef0c00605ee..0f18ce8a9397 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -200,7 +200,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; - struct class_device *clsdev; + struct device *clsdev; int id; mutex_lock(&dvbdev_register_lock); @@ -242,10 +242,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); - clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, - nums2minor(adap->num, type, id)), - adap->device, "dvb%d.%s%d", adap->num, - dnames[type], id); + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -266,8 +265,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + dvbdev->type, dvbdev->id))); list_del (&dvbdev->list_head); kfree (dvbdev->fops); From c252b0511596f76a32c7c64bcc6cc60b3bc1ec3a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:57 -0300 Subject: [PATCH 082/310] V4L/DVB (6019): cx88: Make card database more memory efficient The vmux setting is only two bits, but was taking up a whole 32 in the input description struct. By changing it to a two-bit bitfield, it can fit in what was padding space before and drop the input size by 4 bytes, from 28 to 24. This drops the board description struct, which has 9 inputs, from 280 to 244 bytes. Total driver size decreases by 2108 bytes. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 809126866a3e..78486f90327a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -226,8 +226,8 @@ enum cx88_itype { struct cx88_input { enum cx88_itype type; - unsigned int vmux; u32 gpio0, gpio1, gpio2, gpio3; + unsigned int vmux:2; unsigned int extadc:1; }; From b09a79f5848f2143a8ffc724910743027d5a70e0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:58 -0300 Subject: [PATCH 083/310] V4L/DVB (6020): cx88: Fix use of uninitialized variable An error message for PCI resource allocation failure used the board type before it was set. Just get rid of the error message, as get_ressources() [sic] already prints one. Format that error message better, and add the pci function and subsystem information to better associate the error with what caused it. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index f31ec96924b9..055264b9cd61 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1077,8 +1077,11 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci) pci_resource_len(pci,0), core->name)) return 0; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - core->name,(unsigned long long)pci_resource_start(pci,0)); + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; } @@ -1115,12 +1118,6 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { - printk(KERN_ERR "CORE %s No more PCI ressources for " - "subsystem: %04x:%04x, board: %s\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, - cx88_boards[core->board].name); - cx88_devcount--; goto fail_free; } From 6a59d64c5cc302e0139ddb1f5e57afceecb14368 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:57 -0300 Subject: [PATCH 084/310] V4L/DVB (6021): cx88: Copy board information into card state The cx88 driver state stored the ID of the board type in core->board. Every time the driver need to get some information about the board configuration, it uses the board number as an index into board configuration array. This patch changes it so that the board number is in core->boardnr, and core->board is a copy of the board configuration information. This allows access to board information without the extra indirection. e.g. cx88_boards[core->board].mpeg becomes core->board.mpeg. This has a number of advantages: - The code is simpler to write. - It compiles to be smaller and faster, without needing the extra array lookup to get at the board information. - The cx88_boards array no longer needs to be exported to all cx88 modules. - The boards array can be made const - It should be possible to avoid keeping the (large) cx88_boards array around after the module is loaded. - If module parameters or eeprom info override some board configuration setting, it's not necessary to modify the boards array, which would affect all boards of the same type. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 18 +++---- drivers/media/video/cx88/cx88-cards.c | 27 +++++----- drivers/media/video/cx88/cx88-core.c | 45 +++++++--------- drivers/media/video/cx88/cx88-dvb.c | 10 ++-- drivers/media/video/cx88/cx88-i2c.c | 24 ++++----- drivers/media/video/cx88/cx88-input.c | 11 ++-- drivers/media/video/cx88/cx88-mpeg.c | 22 ++++---- drivers/media/video/cx88/cx88-tvaudio.c | 4 +- drivers/media/video/cx88/cx88-video.c | 63 +++++++++++----------- drivers/media/video/cx88/cx88-vp3054-i2c.c | 4 +- drivers/media/video/cx88/cx88.h | 13 ++--- 11 files changed, 112 insertions(+), 129 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f2fcdb92ecce..74e3eb945751 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -734,14 +734,14 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -990,7 +990,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8802_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; f->type = V4L2_TUNER_ANALOG_TV; @@ -1028,7 +1028,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1049,7 +1049,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1246,7 +1246,7 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* By default, core setup will leave the cx22702 out of reset, on the bus. * We left the hardware on power up with the cx22702 active. @@ -1268,7 +1268,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Exit leaving the cx23416 on the bus */ break; @@ -1316,13 +1316,13 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) + if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD)) goto fail_core; dev->width = 720; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1fc71a78b926..8be90ad4e910 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -30,7 +30,7 @@ /* ------------------------------------------------------------------ */ /* board config info */ -struct cx88_board cx88_boards[] = { +const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1687,12 +1687,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) return; } - core->has_radio = 1; - core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; + core->board.tuner_type = (eeprom_data[6] == 0x13) ? + TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3; printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", - core->name, core->tuner_type, eeprom_data[0]); + core->name, core->board.tuner_type, eeprom_data[0]); } static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) @@ -1700,9 +1700,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) struct tveeprom tv; tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); - core->tuner_type = tv.tuner_type; + core->board.tuner_type = tv.tuner_type; core->tuner_formats = tv.tuner_formats; - core->has_radio = tv.has_radio; + core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; /* Make sure we support the board model */ switch (tv.model) @@ -1792,8 +1792,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) name ? name : "unknown"); if (NULL == name) return; - core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id; - core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm; + core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; + core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? + CX88_RADIO : 0; } /* ----------------------------------------------------------------------- */ @@ -1860,7 +1861,7 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) void cx88_card_setup_pre_i2c(struct cx88_core *core) { - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ /* We leave here with the 702 on the bus */ @@ -1883,7 +1884,7 @@ void cx88_card_setup(struct cx88_core *core) tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); } - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) @@ -1927,7 +1928,7 @@ void cx88_card_setup(struct cx88_core *core) msleep(1); cx_set(MO_GP0_IO, 0x00000101); if (0 == core->i2c_rc && - core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) + core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) dvico_fusionhdtv_hybrid_init(core); break; case CX88_BOARD_KWORLD_DVB_T: @@ -1965,14 +1966,10 @@ void cx88_card_setup(struct cx88_core *core) } break; } - if (cx88_boards[core->board].radio.type == CX88_RADIO) - core->has_radio = 1; } /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx88_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 055264b9cd61..ece788bd3d55 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -738,7 +738,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig value |= (1 << 15); value |= (1 << 16); } - if (INPUT(core->input)->type == CX88_VMUX_SVIDEO) + if (INPUT(core->input).type == CX88_VMUX_SVIDEO) value |= (1 << 13) | (1 << 5); if (V4L2_FIELD_INTERLACED == field) value |= (1 << 3); // VINT (interlaced vertical scaling) @@ -833,7 +833,7 @@ static int set_tvaudio(struct cx88_core *core) { v4l2_std_id norm = core->tvnorm; - if (CX88_VMUX_TELEVISION != INPUT(core->input)->type) + if (CX88_VMUX_TELEVISION != INPUT(core->input).type) return 0; if (V4L2_STD_PAL_BG & norm) { @@ -1067,7 +1067,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, vfd->dev = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - core->name, type, cx88_boards[core->board].name); + core->name, type, core->board.name); return vfd; } @@ -1130,39 +1130,34 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->bmmio = (u8 __iomem *)core->lmmio; /* board config */ - core->board = UNSET; + core->boardnr = UNSET; if (card[core->nr] < cx88_bcount) - core->board = card[core->nr]; - for (i = 0; UNSET == core->board && i < cx88_idcount; i++) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) - core->board = cx88_subids[i].card; - if (UNSET == core->board) { - core->board = CX88_BOARD_UNKNOWN; + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, - pci->subsystem_device,cx88_boards[core->board].name, - core->board, card[core->nr] == core->board ? + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? "insmod option" : "autodetected"); - core->tuner_type = tuner[core->nr]; - core->radio_type = radio[core->nr]; - if (UNSET == core->tuner_type) - core->tuner_type = cx88_boards[core->board].tuner_type; - if (UNSET == core->radio_type) - core->radio_type = cx88_boards[core->board].radio_type; - if (!core->tuner_addr) - core->tuner_addr = cx88_boards[core->board].tuner_addr; - if (!core->radio_addr) - core->radio_addr = cx88_boards[core->board].radio_addr; + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->tuner_type, core->tuner_addr<<1, - core->radio_type, core->radio_addr<<1); - - core->tda9887_conf = cx88_boards[core->board].tda9887_conf; + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 1773b40467dc..d98b90721019 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -378,7 +378,7 @@ static int dvb_register(struct cx8802_dev *dev) dev->ts_gen_cntrl = 0x0c; /* init frontend */ - switch (dev->core->board) { + switch (dev->core->boardnr) { case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, @@ -653,7 +653,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* We arrive here with either the cx23416 or the cx22702 * on the bus. Take the bus from the cx23416 and enable the @@ -676,7 +676,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Do Nothing, leave the cx22702 on the bus. */ break; @@ -694,13 +694,13 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) + if (!(core->board.mpeg & CX88_MPEG_DVB)) goto fail_core; /* If vp3054 isn't enabled, a stub will just return 0 */ diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 78bbcfab9670..6b42dea860fd 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -108,28 +108,28 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; - if (core->radio_type != UNSET) { - if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) { + if (core->board.radio_type != UNSET) { + if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->radio_type; - tun_setup.addr = core->radio_addr; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tuner_type != UNSET) { - if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) { + if (core->board.tuner_type != UNSET) { + if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->tuner_type; - tun_setup.addr = core->tuner_addr; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf); + if (core->board.tda9887_conf) + client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); return 0; } @@ -204,9 +204,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, sizeof(core->i2c_algo)); - if (core->tuner_type != TUNER_ABSENT) + if (core->board.tuner_type != TUNER_ABSENT) core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; - if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) + if (core->board.mpeg & CX88_MPEG_DVB) core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL; core->i2c_adap.dev.parent = &pci->dev; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index f5d4a565346e..120f56857f0e 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -74,7 +74,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* read gpio value */ gpio = cx_read(ir->gpio_addr); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_NPGTECH_REALTV_TOP10FM: /* This board apparently uses a combination of 2 GPIO to represent the keys. Additionally, the second GPIO @@ -113,7 +113,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) (gpio & ir->mask_keydown) ? " down" : "", (gpio & ir->mask_keyup) ? " up" : ""); - if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) { + if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { u32 gpio_key = cx_read(MO_GP0_IO); data = (data << 4) | ((gpio_key & 0xf0) >> 4); @@ -204,7 +204,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input = input_dev; /* detect & configure */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_KWORLD_DVB_T_CX22702: @@ -314,8 +314,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } /* init input device */ - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", - cx88_boards[core->board].name); + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); @@ -406,7 +405,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dump_samples(ir->samples, ir->scount); /* decode it */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index c34158d9dcc1..1df245ace2d0 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -55,9 +55,9 @@ static void request_module_async(struct work_struct *work) { struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) + if (dev->core->board.mpeg & CX88_MPEG_DVB) request_module("cx88-dvb"); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) + if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD) request_module("cx88-blackbird"); } @@ -95,7 +95,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); if ( (core->active_type_id == CX88_MPEG_DVB) && - (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { + (core->board.mpeg & CX88_MPEG_DVB) ) { dprintk( 1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ @@ -103,7 +103,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); cx_write(MO_PINMUX_IO, 0x00); cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: @@ -124,7 +124,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && - (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { + (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { dprintk( 1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ @@ -138,7 +138,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); } else { printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, - cx88_boards[core->board].mpeg ); + core->board.mpeg ); return -EINVAL; } @@ -689,8 +689,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -741,8 +741,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -782,7 +782,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); err = -ENODEV; - if (!cx88_boards[core->board].mpeg) + if (!core->board.mpeg) goto fail_core; err = -ENOMEM; diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 1cc2d286a1cb..99e120483ecd 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -140,7 +140,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_RATE_THRES_DMD, 0x000000C0); cx88_start_audio_dma(core); - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ @@ -149,7 +149,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_I2SCNTL, 0); /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ } - if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) { + if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { ctl |= EN_DAC_ENABLE; cx_write(AUD_CTL, ctl); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 58ec76be436c..b0dd4313a841 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -368,17 +368,17 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) /* struct cx88_core *core = dev->core; */ dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", - input, INPUT(input)->vmux, - INPUT(input)->gpio0,INPUT(input)->gpio1, - INPUT(input)->gpio2,INPUT(input)->gpio3); + input, INPUT(input).vmux, + INPUT(input).gpio0,INPUT(input).gpio1, + INPUT(input).gpio2,INPUT(input).gpio3); core->input = input; - cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14); - cx_write(MO_GP3_IO, INPUT(input)->gpio3); - cx_write(MO_GP0_IO, INPUT(input)->gpio0); - cx_write(MO_GP1_IO, INPUT(input)->gpio1); - cx_write(MO_GP2_IO, INPUT(input)->gpio2); + cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); + cx_write(MO_GP3_IO, INPUT(input).gpio3); + cx_write(MO_GP0_IO, INPUT(input).gpio0); + cx_write(MO_GP1_IO, INPUT(input).gpio1); + cx_write(MO_GP2_IO, INPUT(input).gpio2); - switch (INPUT(input)->type) { + switch (INPUT(input).type) { case CX88_VMUX_SVIDEO: cx_set(MO_AFECFG_IO, 0x00000001); cx_set(MO_INPUT_FORMAT, 0x00010010); @@ -393,9 +393,9 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { /* sets sound input from external adc */ - if (INPUT(input)->extadc) + if (INPUT(input).extadc) cx_set(AUD_CTL, EN_I2SIN_ENABLE); else cx_clear(AUD_CTL, EN_I2SIN_ENABLE); @@ -767,12 +767,11 @@ static int video_open(struct inode *inode, struct file *file) fh); if (fh->radio) { - int board = core->board; dprintk(1,"video_open: setting radio device\n"); - cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); - cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); - cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); - cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); + cx_write(MO_GP3_IO, core->board.radio.gpio3); + cx_write(MO_GP0_IO, core->board.radio.gpio0); + cx_write(MO_GP1_IO, core->board.radio.gpio1); + cx_write(MO_GP2_IO, core->board.radio.gpio2); core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); @@ -1078,8 +1077,7 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = @@ -1087,7 +1085,7 @@ static int vidioc_querycap (struct file *file, void *priv, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1221,14 +1219,14 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) n = i->index; if (n >= 4) return -EINVAL; - if (0 == INPUT(n)->type) + if (0 == INPUT(n).type) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n)->type]); - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || - (CX88_VMUX_CABLE == INPUT(n)->type)) + strcpy(i->name,iname[INPUT(n).type]); + if ((CX88_VMUX_TELEVISION == INPUT(n).type) || + (CX88_VMUX_CABLE == INPUT(n).type)) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX88_NORMS; return 0; @@ -1297,7 +1295,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1318,7 +1316,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1333,7 +1331,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ @@ -1348,7 +1346,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, int cx88_set_freq (struct cx88_core *core, struct v4l2_frequency *f) { - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -1419,8 +1417,7 @@ static int radio_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; @@ -1828,10 +1825,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ - if (TUNER_ABSENT != core->tuner_type) + if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775) + if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); /* register v4l devices */ @@ -1858,7 +1855,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s/0: registered device vbi%d\n", core->name,dev->vbi_dev->minor & 0x1f); - if (core->has_radio) { + if (core->board.radio.type == CX88_RADIO) { dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, @@ -1884,7 +1881,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, mutex_unlock(&core->lock); /* start tvaudio thread */ - if (core->tuner_type != TUNER_ABSENT) { + if (core->board.tuner_type != TUNER_ABSENT) { core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index cd0877636a32..f76ca9e2eebf 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -111,7 +111,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c; int rc; - if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return 0; dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); @@ -152,7 +152,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; if (vp3054_i2c == NULL || - dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; i2c_del_adapter(&vp3054_i2c->adap); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 78486f90327a..3636ec26de59 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -250,7 +250,7 @@ struct cx88_subid { u32 card; }; -#define INPUT(nr) (&cx88_boards[core->board].input[nr]) +#define INPUT(nr) (core->board.input[nr]) /* ----------------------------------------------------------- */ /* device / file handle status */ @@ -304,13 +304,8 @@ struct cx88_core { u32 i2c_state, i2c_rc; /* config info -- analog */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - unsigned int tda9887_conf; - unsigned int has_radio; + unsigned int boardnr; + struct cx88_board board; /* Supported V4L _STD_ tuner formats */ unsigned int tuner_formats; @@ -585,7 +580,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern struct cx88_board cx88_boards[]; +extern const struct cx88_board cx88_boards[]; extern const unsigned int cx88_bcount; extern struct cx88_subid cx88_subids[]; From bbc83597dfe3093b161014e6ebb351279eabaa7c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:58 -0300 Subject: [PATCH 085/310] V4L/DVB (6022): cx88: Move card core creation from cx88-core.c to cx88-cards.c A lot of code in cx88-cards.c was only used by cx88-core.c when the core state is first allocated and initialized. Moving that task to cx88-cards makes the driver simpler and the files more self contained. - Module parameters tuner, radio, card, and latency move to cx88-cards.c - cx88_boards is made static - cx88_subids is made static and const - cx88_bcount is eliminated - cx88_idcount is eliminated - cx88_card_list() is made static - cx88_card_setup_pre_i2c() is made static - cx88_card_setup() is made static - cx88_pci_quirks() is moved from cx88-core to cx88-cards The function argument "char *name" is made const too - get_ressources() is moved from cx88-core to cx88-cards, and renamed to cx88_get_resources() - The code to allocate and initialize the core state struct and the chip is moved out of cx88-core.c:cx88_get_core() and into a new function in cx88-cards.c, cx88_core_create(). This makes both functions simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 168 ++++++++++++++++++++++++-- drivers/media/video/cx88/cx88-core.c | 161 ++---------------------- drivers/media/video/cx88/cx88.h | 12 +- 3 files changed, 171 insertions(+), 170 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 8be90ad4e910..6204a453c11e 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -27,10 +27,26 @@ #include "cx88.h" +static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; + +module_param_array(tuner, int, NULL, 0444); +module_param_array(radio, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(tuner,"tuner type"); +MODULE_PARM_DESC(radio,"radio tuner type"); +MODULE_PARM_DESC(card,"card type"); + +static unsigned int latency = UNSET; +module_param(latency,int,0444); +MODULE_PARM_DESC(latency,"pci latency timer"); + /* ------------------------------------------------------------------ */ /* board config info */ -const struct cx88_board cx88_boards[] = { +static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1355,12 +1371,11 @@ const struct cx88_board cx88_boards[] = { }}, }, }; -const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); /* ------------------------------------------------------------------ */ /* PCI subsystem IDs */ -struct cx88_subid cx88_subids[] = { +static const struct cx88_subid cx88_subids[] = { { .subvendor = 0x0070, .subdevice = 0x3400, @@ -1666,7 +1681,6 @@ struct cx88_subid cx88_subids[] = { .card = CX88_BOARD_ADSTECH_PTV_390, }, }; -const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); /* ----------------------------------------------------------------------- */ /* some leadtek specific stuff */ @@ -1833,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) /* ----------------------------------------------------------------------- */ -void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) +static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; @@ -1854,12 +1868,12 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) } printk("%s: Here is a list of valid choices for the card= insmod option:\n", core->name); - for (i = 0; i < cx88_bcount; i++) + for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) printk("%s: card=%d -> %s\n", core->name, i, cx88_boards[i].name); } -void cx88_card_setup_pre_i2c(struct cx88_core *core) +static void cx88_card_setup_pre_i2c(struct cx88_core *core) { switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1875,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core) } } -void cx88_card_setup(struct cx88_core *core) +static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; @@ -1970,6 +1984,144 @@ void cx88_card_setup(struct cx88_core *core) /* ------------------------------------------------------------------ */ +static int cx88_pci_quirks(const char *name, struct pci_dev *pci) +{ + unsigned int lat = UNSET; + u8 ctrl = 0; + u8 value; + + /* check pci quirks */ + if (pci_pci_problems & PCIPCI_TRITON) { + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_NATOMA) { + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VIAETBF) { + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VSFX) { + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", + name); + ctrl |= CX88X_EN_VSFX; + } +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + name); + lat = 0x0A; + } +#endif + + /* check insmod options */ + if (UNSET != latency) + lat = latency; + + /* apply stuff */ + if (ctrl) { + pci_read_config_byte(pci, CX88X_DEVCTRL, &value); + value |= ctrl; + pci_write_config_byte(pci, CX88X_DEVCTRL, value); + } + if (UNSET != lat) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + name, latency); + pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); + } + return 0; +} + +int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) +{ + if (request_mem_region(pci_resource_start(pci,0), + pci_resource_len(pci,0), + core->name)) + return 0; + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); + return -EBUSY; +} + +/* Allocate and initialize the cx88 core struct. One should hold the + * devlist mutex before calling this. */ +struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) +{ + struct cx88_core *core; + int i; + + core = kzalloc(sizeof(*core), GFP_KERNEL); + + atomic_inc(&core->refcount); + core->pci_bus = pci->bus->number; + core->pci_slot = PCI_SLOT(pci->devfn); + core->pci_irqmask = 0x00fc00; + mutex_init(&core->lock); + + core->nr = nr; + sprintf(core->name, "cx88[%d]", core->nr); + if (0 != cx88_get_resources(core, pci)) { + kfree(core); + return NULL; + } + + /* PCI stuff */ + cx88_pci_quirks(core->name, pci); + core->lmmio = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + core->bmmio = (u8 __iomem *)core->lmmio; + + /* board config */ + core->boardnr = UNSET; + if (card[core->nr] < ARRAY_SIZE(cx88_boards)) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) + if (pci->subsystem_vendor == cx88_subids[i].subvendor && + pci->subsystem_device == cx88_subids[i].subdevice) + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; + cx88_card_list(core, pci); + } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? + "insmod option" : "autodetected"); + + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; + + printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); + + /* init hardware */ + cx88_reset(core); + cx88_card_setup_pre_i2c(core); + cx88_i2c_init(core, pci); + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); + cx88_card_setup(core); + cx88_ir_init(core, pci); + + return core; +} + +/* ------------------------------------------------------------------ */ + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ece788bd3d55..0765e9db5339 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -52,22 +52,6 @@ static unsigned int core_debug = 0; module_param(core_debug,int,0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); -static unsigned int latency = UNSET; -module_param(latency,int,0444); -MODULE_PARM_DESC(latency,"pci latency timer"); - -static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; - -module_param_array(tuner, int, NULL, 0444); -module_param_array(radio, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - -MODULE_PARM_DESC(tuner,"tuner type"); -MODULE_PARM_DESC(radio,"radio tuner type"); -MODULE_PARM_DESC(card,"card type"); - static unsigned int nicam = 0; module_param(nicam,int,0644); MODULE_PARM_DESC(nicam,"tv audio is nicam"); @@ -997,61 +981,6 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) /* ------------------------------------------------------------------ */ -static int cx88_pci_quirks(char *name, struct pci_dev *pci) -{ - unsigned int lat = UNSET; - u8 ctrl = 0; - u8 value; - - /* check pci quirks */ - if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_NATOMA) { - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VIAETBF) { - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VSFX) { - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", - name); - ctrl |= CX88X_EN_VSFX; - } -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - name); - lat = 0x0A; - } -#endif - - /* check insmod options */ - if (UNSET != latency) - lat = latency; - - /* apply stuff */ - if (ctrl) { - pci_read_config_byte(pci, CX88X_DEVCTRL, &value); - value |= ctrl; - pci_write_config_byte(pci, CX88X_DEVCTRL, value); - } - if (UNSET != lat) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - name, latency); - pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); - } - return 0; -} - -/* ------------------------------------------------------------------ */ - struct video_device *cx88_vdev_init(struct cx88_core *core, struct pci_dev *pci, struct video_device *template, @@ -1071,25 +1000,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return vfd; } -static int get_ressources(struct cx88_core *core, struct pci_dev *pci) -{ - if (request_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0), - core->name)) - return 0; - printk(KERN_ERR - "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", - core->name, PCI_FUNC(pci->devfn), - (unsigned long long)pci_resource_start(pci, 0), - pci->subsystem_vendor, pci->subsystem_device); - return -EBUSY; -} - struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; struct list_head *item; - int i; mutex_lock(&devlist); list_for_each(item,&cx88_devlist) { @@ -1099,82 +1013,23 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) if (PCI_SLOT(pci->devfn) != core->pci_slot) continue; - if (0 != get_ressources(core,pci)) - goto fail_unlock; + if (0 != cx88_get_resources(core, pci)) { + mutex_unlock(&devlist); + return NULL; + } atomic_inc(&core->refcount); mutex_unlock(&devlist); return core; } - core = kzalloc(sizeof(*core),GFP_KERNEL); - if (NULL == core) - goto fail_unlock; - atomic_inc(&core->refcount); - core->pci_bus = pci->bus->number; - core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; - mutex_init(&core->lock); - - core->nr = cx88_devcount++; - sprintf(core->name,"cx88[%d]",core->nr); - if (0 != get_ressources(core,pci)) { - cx88_devcount--; - goto fail_free; + core = cx88_core_create(pci, cx88_devcount); + if (NULL != core) { + cx88_devcount++; + list_add_tail(&core->devlist, &cx88_devlist); } - list_add_tail(&core->devlist,&cx88_devlist); - - /* PCI stuff */ - cx88_pci_quirks(core->name, pci); - core->lmmio = ioremap(pci_resource_start(pci,0), - pci_resource_len(pci,0)); - core->bmmio = (u8 __iomem *)core->lmmio; - - /* board config */ - core->boardnr = UNSET; - if (card[core->nr] < cx88_bcount) - core->boardnr = card[core->nr]; - for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) - if (pci->subsystem_vendor == cx88_subids[i].subvendor && - pci->subsystem_device == cx88_subids[i].subdevice) - core->boardnr = cx88_subids[i].card; - if (UNSET == core->boardnr) { - core->boardnr = CX88_BOARD_UNKNOWN; - cx88_card_list(core,pci); - } - - memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, core->board.name, - core->boardnr, card[core->nr] == core->boardnr ? - "insmod option" : "autodetected"); - - if (tuner[core->nr] != UNSET) - core->board.tuner_type = tuner[core->nr]; - if (radio[core->nr] != UNSET) - core->board.radio_type = radio[core->nr]; - - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); - - /* init hardware */ - cx88_reset(core); - cx88_card_setup_pre_i2c(core); - cx88_i2c_init(core,pci); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); - cx88_card_setup(core); - cx88_ir_init(core,pci); mutex_unlock(&devlist); return core; - -fail_free: - kfree(core); -fail_unlock: - mutex_unlock(&devlist); - return NULL; } void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3636ec26de59..80e49f986fbb 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -580,15 +580,9 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern const struct cx88_board cx88_boards[]; -extern const unsigned int cx88_bcount; - -extern struct cx88_subid cx88_subids[]; -extern const unsigned int cx88_idcount; - -extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci); -extern void cx88_card_setup(struct cx88_core *core); -extern void cx88_card_setup_pre_i2c(struct cx88_core *core); +extern int cx88_get_resources(const struct cx88_core *core, + struct pci_dev *pci); +extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); /* ----------------------------------------------------------- */ /* cx88-tvaudio.c */ From 5772f81326904f2bfbb2bf2f365b3fb36ee3b7d8 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:59 -0300 Subject: [PATCH 086/310] V4L/DVB (6023): cx88: Clean up some ugly and inconsistent printk()s Get rid of the "CORE" prefix from cx88 printks. It was only used a few times, and it makes it look like they're coming from the kernel core or something. Fix the message, "TV tuner 60 at 0x1fe, Radio tuner -1 at 0x1fe", by adding a "cx88[0]" prefix to be consistent, and to keep people who grep their dmesg output for cx88 from missing it. Get rid of the addresses, which are always wrong. The addresses are always set to -1, but because it's an unsigned 8-bit value, the left shift converts it to the nonsense address 0x1fe. In the cx8802 driver, some cut and pasted code prefixed lines with "CORE cx88[0]:", which has been changed to "cx88[0]/2:" like the other printks from the cx8802 driver. Also fix some ugly printks in the cx8802 driver that used __FUNCTION__ for KERN_INFO and KERN_ERR messages. The changed printks in cx88-mpeg.c also needed lots of whitespace and 80-column fixes. A bunch of misc changes in cx88-dvb.c and cx88-video.c to add message levels or a consistent "cx88[?]/2" or "cx88[?]/0" prefix. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 7 ++--- drivers/media/video/cx88/cx88-dvb.c | 13 +++++---- drivers/media/video/cx88/cx88-mpeg.c | 42 ++++++++++++++++----------- drivers/media/video/cx88/cx88-video.c | 30 +++++++++---------- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6204a453c11e..e73e8c96d5b9 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2094,7 +2094,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, pci->subsystem_device, core->board.name, core->boardnr, card[core->nr] == core->boardnr ? @@ -2105,9 +2105,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (radio[core->nr] != UNSET) core->board.radio_type = radio[core->nr]; - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); + printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n", + core->name, core->board.tuner_type, core->board.radio_type); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index d98b90721019..00d0e43785a0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -482,7 +482,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap, DVB_PLL_FMD1216ME); } #else - printk("%s: built without vp3054 support\n", dev->core->name); + printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name); #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: @@ -625,12 +625,12 @@ static int dvb_register(struct cx8802_dev *dev) } break; default: - printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); break; } if (NULL == dev->dvb.frontend) { - printk("%s: frontend initialization failed\n",dev->core->name); + printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name); return -1; } @@ -709,7 +709,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) goto fail_core; /* dvb stuff */ - printk("%s/2: cx2388x based dvb card\n", core->name); + printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -718,7 +718,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dev); err = dvb_register(dev); if (err != 0) - printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", + core->name, err); fail_core: return err; @@ -747,7 +748,7 @@ static struct cx8802_driver cx8802_dvb_driver = { static int dvb_init(void) { - printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1df245ace2d0..5da47e251e66 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -675,22 +675,24 @@ int cx8802_register_driver(struct cx8802_driver *drv) struct list_head *list; int err = 0, i = 0; - printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + printk(KERN_INFO + "cx88/2: registering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); if ((err = cx8802_check_driver(drv)) != 0) { - printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); + printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); return err; } list_for_each(list,&cx8802_devlist) { h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -712,7 +714,9 @@ int cx8802_register_driver(struct cx8802_driver *drv) list_add_tail(&driver->devlist,&h->drvlist.devlist); mutex_unlock(&drv->core->lock); } else { - printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR + "%s/2: cx8802 probe failed, err = %d\n", + h->core->name, err); } } @@ -732,17 +736,20 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) struct list_head *list2, *q; int err = 0, i = 0; - printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); + printk(KERN_INFO + "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); list_for_each(list,&cx8802_devlist) { i++; h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -757,7 +764,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) list_del(list2); mutex_unlock(&drv->core->lock); } else - printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", h->core->name, err); } @@ -865,7 +873,7 @@ static struct pci_driver cx8802_pci_driver = { static int cx8802_init(void) { - printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b0dd4313a841..e158ea2454af 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1818,7 +1818,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, cx8800_irq, IRQF_SHARED | IRQF_DISABLED, core->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + printk(KERN_ERR "%s/0: can't get IRQ %d\n", core->name,pci_dev->irq); goto fail_core; } @@ -1837,7 +1837,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + printk(KERN_ERR "%s/0: can't register video device\n", core->name); goto fail_unreg; } @@ -1848,7 +1848,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register vbi device\n", + printk(KERN_ERR "%s/0: can't register vbi device\n", core->name); goto fail_unreg; } @@ -1861,7 +1861,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register radio device\n", + printk(KERN_ERR "%s/0: can't register radio device\n", core->name); goto fail_unreg; } @@ -1885,8 +1885,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); - printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n", - err); + printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", + core->name, err); } } return 0; @@ -1937,12 +1937,12 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) /* stop video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: suspend video\n", core->name); + printk("%s/0: suspend video\n", core->name); stop_video_dma(dev); del_timer(&dev->vidq.timeout); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: suspend vbi\n", core->name); + printk("%s/0: suspend vbi\n", core->name); cx8800_stop_vbi_dma(dev); del_timer(&dev->vbiq.timeout); } @@ -1968,8 +1968,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) if (dev->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); + printk(KERN_ERR "%s/0: can't enable device\n", + core->name); return err; } @@ -1977,9 +1977,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) } err= pci_set_power_state(pci_dev, PCI_D0); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); - + printk(KERN_ERR "%s/0: can't set power state\n", core->name); pci_disable_device(pci_dev); dev->state.disabled = 1; @@ -1993,11 +1991,11 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* restart video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: resume video\n", core->name); + printk("%s/0: resume video\n", core->name); restart_video_queue(dev,&dev->vidq); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: resume vbi\n", core->name); + printk("%s/0: resume vbi\n", core->name); cx8800_restart_vbi_queue(dev,&dev->vbiq); } spin_unlock(&dev->slock); @@ -2033,7 +2031,7 @@ static struct pci_driver cx8800_pci_driver = { static int cx8800_init(void) { - printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); From 89d969a39da8e9ee5db1c1fb49f55f4206a445ac Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 16 Aug 2007 10:03:18 -0300 Subject: [PATCH 087/310] V4L/DVB (6025): Net_ule(): fix check-after-use The Coverity checker spotted that we'd have already oops'ed if "dev" was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb0..b9c78d03a7fe 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) static unsigned char *ule_where = ule_hist, ule_dump = 0; #endif - if (dev == NULL) { - printk( KERN_ERR "NO netdev struct!\n" ); - return; - } - /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ From 82e67246cd2a860637ee9d27776ad48d32734f6c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 17:49:41 -0300 Subject: [PATCH 088/310] V4L/DVB (6031): Fix for bug 7819: fixed hotplugging for dvbnet The first part of dvb_net_close() is just a cut&paste from dvb_generic_release(), so maybe it would be better to just call dvb_generic_release() instead? Signed-off-by: Trent Piepho Acked-by: Markus Rechberger Acked-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index b9c78d03a7fe..13e2998a4043 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1441,18 +1441,9 @@ static int dvb_net_close(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; - if (!dvbdev) - return -ENODEV; + dvb_generic_release(inode, file); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; - - if(dvbdev->users == 1 && dvbnet->exit==1) { + if(dvbdev->users == 1 && dvbnet->exit == 1) { fops_put(file->f_op); file->f_op = NULL; wake_up(&dvbdev->wait_queue); From fa40b2237ab6ed239967f76432438080232b88fe Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 05:50:22 -0300 Subject: [PATCH 089/310] V4L/DVB (6034): cx88: Add parameter to control radio deemphasis time constant FM radio transmission use a preemphasis/deemphasis scheme to reduce high-frequency noise. The cx88 audio decoder is supposedly set to no deemphasis by the current driver. However, the "no deemphasis" setting doesn't work. On my chip, cx23883, it produces the same result as the 75 us time constant. Maybe the default settings on the cx23881 are for 50 us? Since the deemphasis time constant varies by country, allow setting it via a module parameter. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-tvaudio.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 99e120483ecd..9aee8c51ee27 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -62,6 +62,10 @@ static unsigned int always_analog = 0; module_param(always_analog,int,0644); MODULE_PARM_DESC(always_analog,"force analog audio out"); +static unsigned int radio_deemphasis = 0; +module_param(radio_deemphasis,int,0644); +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " + "0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) if (audio_debug) \ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) @@ -678,6 +682,10 @@ static void set_audio_standard_FM(struct cx88_core *core, }; /* It is enough to leave default values? */ + /* No, it's not! The deemphasis registers are reset to the 75us + * values by default. Analyzing the spectrum of the decoded audio + * reveals that "no deemphasis" is the same as 75 us, while the 50 us + * setting results in less deemphasis. */ static const struct rlist fm_no_deemph[] = { {AUD_POLYPH80SCALEFAC, 0x0003}, @@ -688,6 +696,7 @@ static void set_audio_standard_FM(struct cx88_core *core, set_audio_start(core, SEL_FMRADIO); switch (deemph) { + default: case FM_NO_DEEMPH: set_audio_registers(core, fm_no_deemph); break; @@ -757,7 +766,7 @@ void cx88_set_tvaudio(struct cx88_core *core) set_audio_standard_EIAJ(core); break; case WW_FM: - set_audio_standard_FM(core, FM_NO_DEEMPH); + set_audio_standard_FM(core, radio_deemphasis); break; case WW_NONE: default: From 458b634cd86968032171a4d6db5c89a772ff0348 Mon Sep 17 00:00:00 2001 From: Alan Nisota Date: Sat, 18 Aug 2007 17:52:35 -0300 Subject: [PATCH 090/310] V4L/DVB (6037): Updated GenPix USB driver There are now 4 different versions of the GENPIX USB adapter. The newest 'Skywalker' models are fully self-contained, and need no additional hardware to be used. A very reliable DVB-S card even without using any of the alternate modulatations (which this kernel module does not currently support) The following patch adds support for all 4 versions of the genpix adapter (www.genpix-electronics.com). Signed-off-by: Alan Nisota alannisota@gmail.com Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 7 +- drivers/media/dvb/dvb-usb/gp8psk-fe.c | 84 +++++++++++++--------- drivers/media/dvb/dvb-usb/gp8psk.c | 93 +++++++++++++++++++------ drivers/media/dvb/dvb-usb/gp8psk.h | 32 +++++++-- 4 files changed, 152 insertions(+), 64 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index a16be605c630..43bfe50a2227 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -158,8 +158,11 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 -#define USB_PID_GENPIX_8PSK_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_2 0x0202 +#define USB_PID_GENPIX_SKYWALKER_1 0x0203 +#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 #define USB_PID_SIGMATEK_DVB_110 0x6610 #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 #define USB_PID_OPERA1_COLD 0x2830 diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 6ccbdc9cd772..e37142d9271a 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -17,27 +18,39 @@ struct gp8psk_fe_state { struct dvb_frontend fe; - struct dvb_usb_device *d; - + u8 lock; u16 snr; - - unsigned long next_snr_check; + unsigned long next_status_check; + unsigned long status_check_interval; }; +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 lock; + gp8psk_fe_update_status(st); - if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) - return -EINVAL; - - if (lock) + if (st->lock) *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; else *status = 0; + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; return 0; } @@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 buf[2]; - - if (time_after(jiffies,st->next_snr_check)) { - gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); - *snr = (int)(buf[1]) << 8 | buf[0]; - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (*snr <= 3855) - *snr = (*snr<<4) + *snr; // snr * 17 - else - *snr = 65535; - st->next_snr_check = jiffies + (10*HZ)/1000; - } else { - *snr = st->snr; - } + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; return 0; } static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - return gp8psk_fe_read_snr(fe, strength); + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; } static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 200; return 0; } @@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); - state->next_snr_check = jiffies; + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; return 0; } @@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt return 0; } +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) { struct gp8psk_fe_state* state = fe->demodulator_priv; @@ -235,10 +252,10 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { .info = { - .name = "Genpix 8psk-USB DVB-S", + .name = "Genpix 8psk-to-USB2 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, + .frequency_min = 800000, + .frequency_max = 2250000, .frequency_stepsize = 100, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, @@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .set_tone = gp8psk_fe_set_tone, .set_voltage = gp8psk_fe_set_voltage, .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage }; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 518d67fca5e8..92147ee3e14f 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 } if (ret < 0 || ret != blen) { - warn("usb in operation failed."); + warn("usb in %d operation failed.", req); ret = -EIO; } else ret = 0; @@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) goto out_rel_fw; - info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware); + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); ptr = fw->data; - buf = kmalloc(512, GFP_KERNEL | GFP_DMA); + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); while (ptr[0] != 0xff) { u16 buflen = ptr[0] + 4; @@ -129,25 +130,34 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + if (onoff) { gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & 0x01)) /* started */ + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) return -EINVAL; + } - if (! (status & 0x02)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return EINVAL; + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return EINVAL; - if (! (status & 0x04)) /* LNB Power */ + if (! (status & bmIntersilOn)) /* LNB Power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, &buf, 1)) return EINVAL; - /* Set DVB mode */ - if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return EINVAL; } else { /* Turn off LNB power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) @@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) /* Turn off 8psk power */ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) return -EINVAL; - + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); } return 0; } +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return EINVAL; + return 0; +} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { @@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties; static int gp8psk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; } static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, + .num_device_descs = 4, .devices = { - { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver", + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, .warm_ids = { &gp8psk_usb_table[1], NULL }, }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-CW3K DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, { NULL }, } }; @@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init); module_exit(gp8psk_usb_module_exit); MODULE_AUTHOR("Alan Nisota "); -MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0"); -MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S"); +MODULE_VERSION("1.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index 3eba7061011c..e83a57506cfa 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug; #define TH_COMMAND_IN 0xC0 #define TH_COMMAND_OUT 0xC1 -/* command bytes */ -#define GET_8PSK_CONFIG 0x80 +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ #define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 #define ARM_TRANSFER 0x85 #define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ #define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 -#define START_INTERSIL 0x8A +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ #define SET_LNB_VOLTAGE 0x8B #define SET_22KHZ_TONE 0x8C #define SEND_DISEQC_COMMAND 0x8D #define SET_DVB_MODE 0x8E #define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 /* Satellite modulation modes */ #define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ @@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif From e927b3fa595117c9f4c6dfa241fe7c3a3c596f17 Mon Sep 17 00:00:00 2001 From: Michael Mauch Date: Sat, 18 Aug 2007 18:02:31 -0300 Subject: [PATCH 091/310] V4L/DVB (6038): Trivial: repair mixed parm descs in dvb-usb-init.c Repair modinfo parameter descriptions for force_pid_filter_usage and disable_rc_polling. Signed-off-by: Michael Mauch Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index ffdde83d1e77..cdd717c3fe45 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0 static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); static int dvb_usb_adapter_init(struct dvb_usb_device *d) { From faebb914399ecf8ecfd0e24b96ac90d7381f7e07 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:04:00 -0300 Subject: [PATCH 092/310] V4L/DVB (6039): Typo fix in Nova-TD description Typo fix in Nova-TD description Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 4a3c5467d7e0..0227e7fac3cf 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -944,7 +944,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, From b1139e353c7fc636bfe413f3296ba0284eb60c2e Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:05:31 -0300 Subject: [PATCH 093/310] V4L/DVB (6040): Add IR support for Nova-T Stick Working with Nova-T Stick (70001) with remote control model A415. Untested with other dib0700m/dib0700p devices. Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0227e7fac3cf..063fb5095bda 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -887,7 +887,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[8], NULL }, { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, From 33bc4dea0ece371ccadbac8bf90fd0b8e2803f06 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:36:09 -0300 Subject: [PATCH 094/310] V4L/DVB (6043): ivtv: fix incorrect round-robin implementation Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 88c6f4ff5c6d..a97d55fd2277 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -859,8 +859,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) @@ -877,8 +878,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) From da80be21362376443c6ee9918dfff408e83e0c39 Mon Sep 17 00:00:00 2001 From: Kazuhiko Kawakami Date: Sat, 18 Aug 2007 11:39:28 -0300 Subject: [PATCH 095/310] V4L/DVB (6044): vp27smpx: clarify history of this source. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 8a81fcd13ae9..63002e0ac764 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,8 @@ * * Copyright (C) 2007 Hans Verkuil * - * Based on a tvaudio patch from Kazuhiko Kawakami + * Based on a tvaudio patch from Takahiro Adachi + * and Kazuhiko Kawakami * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 3562c43be8cfd6e300508d7c33acebf3369eacd3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:46:05 -0300 Subject: [PATCH 096/310] V4L/DVB (6045): ivtv: fix handling of INITIALIZE_INPUT fw call The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling, otherwise the computer can freeze or the top-third of the screen can start flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called at the right time and in the right way. In addition the stop capture handling was improved so that the last pending DMA transfer is also processed. Otherwise this would be the first data that arrived when a new capture was started which is not what you want. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 19 ++++++++++------- drivers/media/video/ivtv/ivtv-ioctl.c | 3 +++ drivers/media/video/ivtv/ivtv-streams.c | 28 +++++-------------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 9e867b5229d1..908e640c274d 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -EBUSY; } + if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (atomic_read(&itv->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + kfree(item); + return -EBUSY; + } + } + /* Mark that the radio is being used. */ + set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* We have the radio */ ivtv_mute(itv); /* Switch tuner to radio */ ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* Select the correct audio input (i.e. radio tuner) */ ivtv_audio_set_io(itv); if (itv->hw_flags & IVTV_HW_SAA711X) @@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv) void ivtv_unmute(struct ivtv *itv) { - /* initialize or refresh input */ - if (atomic_read(&itv->capturing) == 0) - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); - if (atomic_read(&itv->capturing)) { + ivtv_msleep_timeout(100, 0); ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index cee6c558c69c..734f2d2ffa62 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_DEBUG_INFO("Input unchanged\n"); break; } + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; + } IVTV_DEBUG_INFO("Changing input from %d to %d\n", itv->active_input, inp); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 405e2e3fcb49..0582b9d57c55 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ + itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, 0); } /* begin_capture */ @@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) int cap_type; unsigned long then; int stopmode; - u32 data[CX2341X_MBOX_MAX_DATA]; if (s->v4l2dev == NULL) return -EINVAL; @@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } then = jiffies; - /* Make sure DMA is complete */ - add_wait_queue(&s->waitq, &wait); - do { - /* check if DMA is pending */ - if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ - (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { - /* Check for last DMA */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); - if (data[0] == 1) { - IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); - break; - } - } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { - break; - } - } while (!ivtv_msleep_timeout(10, 1) && - then + msecs_to_jiffies(2000) > jiffies); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&s->waitq, &wait); + /* Handle any pending interrupts */ + ivtv_msleep_timeout(100, 1); } atomic_dec(&itv->capturing); From f4071b85ea0ca3bd06f63c330562b4cfdffa8473 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 12:07:12 -0300 Subject: [PATCH 097/310] V4L/DVB (6046): ivtv: always steal full frames if out of buffers. When there are no more free buffers, then buffers are stolen from the predma queue. Buffers should be stolen from the head of that queue (which is where the most recently added buffers are) and all buffers belonging to a frame should be stolen. Otherwise 'half-frames' would remain in the queue, which leads to ugly playback and complete sync failure for YUV buffers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 9 ++++- drivers/media/video/ivtv/ivtv-fileops.c | 3 +- drivers/media/video/ivtv/ivtv-irq.c | 5 ++- drivers/media/video/ivtv/ivtv-queue.c | 54 +++++++++++++++---------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 0a1c16ad10bb..f5de2fd01b1a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -356,7 +356,7 @@ struct ivtv_mailbox_data { }; /* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ +#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ /* per-stream, s_flags */ #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ @@ -437,7 +437,8 @@ struct ivtv_dma_page_info { struct ivtv_buffer { struct list_head list; dma_addr_t dma_handle; - unsigned long b_flags; + unsigned short b_flags; + unsigned short dma_xfer_cnt; char *buf; u32 bytesused; @@ -487,6 +488,10 @@ struct ivtv_stream { struct ivtv_queue q_dma; /* waiting for DMA */ struct ivtv_queue q_predma; /* waiting for DMA */ + /* DMA xfer counter, buffers belonging to the same DMA + xfer will have the same dma_xfer_cnt. */ + u16 dma_xfer_cnt; + /* Base Dev SG Array for cx23415/6 */ struct ivtv_SG_element *SGarray; struct ivtv_SG_element *PIOarray; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 908e640c274d..076b0089a2b0 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -247,8 +247,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, /* do we have new data? */ buf = ivtv_dequeue(s, &s->q_full); if (buf) { - if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) + if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) return buf; + buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; if (s->type == IVTV_ENC_STREAM_TYPE_MPG) /* byteswap MPG data */ ivtv_buf_swap(buf); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a97d55fd2277..8644f3dda31e 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -214,6 +214,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->SGarray[idx].src = cpu_to_le32(offset); s->SGarray[idx].size = cpu_to_le32(s->buf_size); buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; size -= buf->bytesused; @@ -286,7 +287,7 @@ static void dma_post(struct ivtv_stream *s) /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ if (s->type == IVTV_ENC_STREAM_TYPE_MPG || s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); + buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; } if (buf) buf->bytesused += s->dma_last_offset; @@ -396,12 +397,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) } itv->vbi.dma_offset = s_vbi->dma_offset; s_vbi->SG_length = 0; + s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } /* Mark last buffer size for Interrupt flag */ s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->dma_xfer_cnt++; if (s->type == IVTV_ENC_STREAM_TYPE_VBI) set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index a04f9387f63d..bff75aeee0a0 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -60,6 +60,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; + buf->dma_xfer_cnt = 0; } spin_lock_irqsave(&s->qlock, flags); list_add_tail(&buf->list, &q->list); @@ -87,7 +88,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) } static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear, int full) + struct ivtv_queue *to, int clear) { struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); @@ -97,13 +98,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, from->bytesused -= buf->bytesused - buf->readpos; /* special handling for q_free */ if (clear) - buf->bytesused = buf->readpos = buf->b_flags = 0; - else if (full) { - /* special handling for stolen buffers, assume - all bytes are used. */ - buf->bytesused = s->buf_size; - buf->readpos = buf->b_flags = 0; - } + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; to->buffers++; to->length += s->buf_size; to->bytesused += buf->bytesused - buf->readpos; @@ -112,7 +107,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. If 'steal' != NULL, then buffers may also taken from that queue if - needed. + needed, but only if 'from' is the free queue. The buffer is automatically cleared if it goes to the free queue. It is also cleared if buffers need to be taken from the 'steal' queue and @@ -133,7 +128,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ int rc = 0; int from_free = from == &s->q_free; int to_free = to == &s->q_free; - int bytes_available; + int bytes_available, bytes_steal; spin_lock_irqsave(&s->qlock, flags); if (needed_bytes == 0) { @@ -142,32 +137,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ } bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; + bytes_steal = (from_free && steal) ? steal->length : 0; - if (bytes_available < needed_bytes) { + if (bytes_available + bytes_steal < needed_bytes) { spin_unlock_irqrestore(&s->qlock, flags); return -ENOMEM; } + while (bytes_available < needed_bytes) { + struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + u16 dma_xfer_cnt = buf->dma_xfer_cnt; + + /* move buffers from the tail of the 'steal' queue to the tail of the + 'from' queue. Always copy all the buffers with the same dma_xfer_cnt + value, this ensures that you do not end up with partial frame data + if one frame is stored in multiple buffers. */ + while (dma_xfer_cnt == buf->dma_xfer_cnt) { + list_move_tail(steal->list.prev, &from->list); + rc++; + steal->buffers--; + steal->length -= s->buf_size; + steal->bytesused -= buf->bytesused - buf->readpos; + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + from->buffers++; + from->length += s->buf_size; + bytes_available += s->buf_size; + if (list_empty(&steal->list)) + break; + buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + } + } if (from_free) { u32 old_length = to->length; while (to->length - old_length < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, 1, 0); + ivtv_queue_move_buf(s, from, to, 1); } } else { u32 old_bytesused = to->bytesused; while (to->bytesused - old_bytesused < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, to_free, rc); + ivtv_queue_move_buf(s, from, to, to_free); } } spin_unlock_irqrestore(&s->qlock, flags); From 37093b1ea600d84fbf7252baf12eedec85ae40f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 19:45:50 -0300 Subject: [PATCH 098/310] V4L/DVB (6047): ivtv: Fix scatter/gather DMA timeouts It turns out that the cx23415/6 DMA engine cannot do scatter/gather DMA reliably. Every so often depending on the phase of the moon and your hardware configuration the cx2341x DMA engine simply chokes on it and you have to reboot to get it working again. This change replaced the scatter/gather DMA by single transfers at a time, where the driver is now responsible for DMA-ing each buffer. UDMA is still done using scatter/gather DMA, that will be fixed soon. Many thanks to Mark Bryars for discovering the link between scatter/gather and the DMA timeouts. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 22 ++- drivers/media/video/ivtv/ivtv-irq.c | 242 ++++++++++++++---------- drivers/media/video/ivtv/ivtv-queue.c | 67 ++++--- drivers/media/video/ivtv/ivtv-queue.h | 8 +- drivers/media/video/ivtv/ivtv-streams.c | 2 +- 5 files changed, 202 insertions(+), 139 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f5de2fd01b1a..e80f9f65a905 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -382,7 +382,6 @@ struct ivtv_mailbox_data { #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ @@ -405,7 +404,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ /* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_SG_element { +struct ivtv_sg_element { u32 src; u32 dst; u32 size; @@ -417,7 +416,7 @@ struct ivtv_user_dma { struct page *map[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; + struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; dma_addr_t SG_handle; int SG_length; @@ -468,6 +467,10 @@ struct ivtv_stream { int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ + u32 pending_offset; + u32 pending_backup; + u64 pending_pts; + u32 dma_offset; u32 dma_backup; u64 dma_pts; @@ -493,10 +496,13 @@ struct ivtv_stream { u16 dma_xfer_cnt; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element *SGarray; - struct ivtv_SG_element *PIOarray; - dma_addr_t SG_handle; - int SG_length; + struct ivtv_sg_element *sg_pending; + struct ivtv_sg_element *sg_processing; + struct ivtv_sg_element *sg_dma; + dma_addr_t sg_handle; + int sg_pending_size; + int sg_processing_size; + int sg_processed; /* SG List of Buffers */ struct scatterlist *SGlist; @@ -637,7 +643,6 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u32 dma_offset; u8 cc_data_odd[256]; u8 cc_data_even[256]; int cc_pos; @@ -724,6 +729,7 @@ struct ivtv { int cur_pio_stream; /* index of stream doing PIO */ u32 dma_data_req_offset; u32 dma_data_req_size; + int dma_retries; int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ spinlock_t lock; /* lock access to this struct */ int search_pack_header; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 8644f3dda31e..9695e5356163 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -60,18 +60,18 @@ static void ivtv_pio_work_handler(struct ivtv *itv) buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_dma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - u32 size = s->PIOarray[i].size & 0x3ffff; + u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size); + memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); } else { - memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size); + memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); } - if (s->PIOarray[i].size & 0x80000000) - break; i++; + if (i == s->sg_processing_size) + break; } write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); } @@ -105,7 +105,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA u32 offset, size; u32 UVoffset = 0, UVsize = 0; int skip_bufs = s->q_predma.buffers; - int idx = s->SG_length; + int idx = s->sg_pending_size; int rc; /* sanity checks */ @@ -123,7 +123,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA case IVTV_ENC_STREAM_TYPE_MPG: offset = data[1]; size = data[2]; - s->dma_pts = 0; + s->pending_pts = 0; break; case IVTV_ENC_STREAM_TYPE_YUV: @@ -131,13 +131,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA size = data[2]; UVoffset = data[3]; UVsize = data[4]; - s->dma_pts = ((u64) data[5] << 32) | data[6]; + s->pending_pts = ((u64) data[5] << 32) | data[6]; break; case IVTV_ENC_STREAM_TYPE_PCM: offset = data[1] + 12; size = data[2] - 12; - s->dma_pts = read_dec(offset - 8) | + s->pending_pts = read_dec(offset - 8) | ((u64)(read_dec(offset - 12)) << 32); if (itv->has_cx23415) offset += IVTV_DECODER_OFFSET; @@ -150,13 +150,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA IVTV_DEBUG_INFO("VBI offset == 0\n"); return -1; } - s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); + s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); break; case IVTV_DEC_STREAM_TYPE_VBI: size = read_dec(itv->vbi.dec_start + 4) + 8; offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->dma_pts = 0; + s->pending_pts = 0; offset += IVTV_DECODER_OFFSET; break; default: @@ -165,17 +165,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->SG_length == 0) { + if (s->sg_pending_size == 0) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); + s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); } else { - s->dma_backup = read_enc(offset); + s->pending_backup = read_enc(offset); write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); } - s->dma_offset = offset; + s->pending_offset = offset; } bytes_needed = size; @@ -202,7 +202,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } s->buffers_stolen = rc; - /* got the buffers, now fill in SGarray (DMA) */ + /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); list_for_each(p, &s->q_predma.list) { @@ -210,9 +210,9 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (skip_bufs-- > 0) continue; - s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].src = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(s->buf_size); + s->sg_pending[idx].dst = buf->dma_handle; + s->sg_pending[idx].src = offset; + s->sg_pending[idx].size = s->buf_size; buf->bytesused = (size < s->buf_size) ? size : s->buf_size; buf->dma_xfer_cnt = s->dma_xfer_cnt; @@ -230,7 +230,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } idx++; } - s->SG_length = idx; + s->sg_pending_size = idx; return 0; } @@ -332,9 +332,9 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) offset = uv_offset; y_done = 1; } - s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].dst = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(buf->bytesused); + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; offset += buf->bytesused; bytes_written += buf->bytesused; @@ -343,10 +343,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) ivtv_buf_sync_for_device(s, buf); idx++; } - s->SG_length = idx; - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->sg_pending_size = idx; /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); @@ -362,6 +359,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) spin_unlock_irqrestore(&itv->dma_reg_lock, flags); } +static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); +} + +static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); +} + /* start the encoder DMA */ static void ivtv_dma_enc_start(struct ivtv_stream *s) { @@ -375,8 +400,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); if (ivtv_use_dma(s)) - s->SGarray[s->SG_length - 1].size = - cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); + s->sg_pending[s->sg_pending_size - 1].size += 256; /* If this is an MPEG stream, and VBI data is also pending, then append the VBI DMA to the MPEG DMA and transfer both sets of data at once. @@ -387,45 +411,39 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) sure we only use the MPEG DMA to transfer the VBI DMA if both are in use. This way no conflicts occur. */ clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && - s->SG_length + s_vbi->SG_length <= s->buffers) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && + s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); if (ivtv_use_dma(s_vbi)) - s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); - for (i = 0; i < s_vbi->SG_length; i++) { - s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; + s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; + for (i = 0; i < s_vbi->sg_pending_size; i++) { + s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; } - itv->vbi.dma_offset = s_vbi->dma_offset; - s_vbi->SG_length = 0; + s_vbi->dma_offset = s_vbi->pending_offset; + s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); s->dma_xfer_cnt++; - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - else - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + s->dma_offset = s->pending_offset; + s->dma_backup = s->pending_backup; + s->dma_pts = s->pending_pts; if (ivtv_use_pio(s)) { - for (i = 0; i < s->SG_length; i++) { - s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src); - s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size); - } set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); set_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = s->type; } else { - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_enc_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -439,10 +457,15 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s) if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); - /* put SG Handle into register 0x0c */ - write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_dec_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -453,27 +476,42 @@ static void ivtv_irq_dma_read(struct ivtv *itv) { struct ivtv_stream *s = NULL; struct ivtv_buffer *buf; - int hw_stream_type; + int hw_stream_type = 0; IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - del_timer(&itv->dma_timer); - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); + return; } - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - hw_stream_type = 2; - } - else { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - hw_stream_type = 0; - } - IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + s = &itv->streams[itv->cur_dma_stream]; ivtv_stream_sync_for_cpu(s); + if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { + IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", + read_reg(IVTV_REG_DMASTATUS), + s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_dec_start_xfer(s); + return; + } + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + hw_stream_type = 2; + IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + /* For some reason must kick the firmware, like PIO mode, I think this tells the firmware we are done and the size of the xfer so it can calculate what we need next. @@ -490,6 +528,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) } wake_up(&s->waitq); } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -501,33 +540,44 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; - del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); - if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) - data[1] = 3; - else if (data[1] > 2) + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); + if (itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); return; - s = &itv->streams[ivtv_stream_map[data[1]]]; - if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); } - s->SG_length = 0; + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (data[0] & 0x18) { + IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], + s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_enc_start_xfer(s); + return; + } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; dma_post(s); - ivtv_stream_sync_for_cpu(s); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } + s->sg_processing_size = 0; + s->sg_processed = 0; wake_up(&itv->dma_waitq); } @@ -541,8 +591,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->SG_length = 0; - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); @@ -554,13 +603,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); clear_bit(IVTV_F_I_PIO, &itv->i_flags); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } wake_up(&itv->dma_waitq); } @@ -572,19 +616,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv) del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; /* retry */ - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) ivtv_dma_dec_start(s); else ivtv_dma_enc_start(s); return; } + if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + ivtv_udma_start(itv); + return; + } clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -628,14 +676,14 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) DMA the data. Since at most four VBI DMA buffers are available, we just drop the old requests when there are already three requests queued. */ - if (s->SG_length > 2) { + if (s->sg_pending_size > 2) { struct list_head *p; list_for_each(p, &s->q_predma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); ivtv_buf_sync_for_cpu(s, buf); } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->SG_length = 0; + s->sg_pending_size = 0; } /* if we can append the data, and the MPEG stream isn't capturing, then start a DMA request for just the VBI data. */ diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index bff75aeee0a0..d9a1478ca1f7 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -195,7 +195,7 @@ void ivtv_flush_queues(struct ivtv_stream *s) int ivtv_stream_alloc(struct ivtv_stream *s) { struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; + int SGsize = sizeof(struct ivtv_sg_element) * s->buffers; int i; if (s->buffers == 0) @@ -205,27 +205,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (ivtv_might_use_pio(s)) { - s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->PIOarray == NULL) { - IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name); - return -ENOMEM; - } - } - - /* Allocate DMA SG Arrays */ - s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->SGarray == NULL) { - IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); - if (ivtv_might_use_pio(s)) { - kfree(s->PIOarray); - s->PIOarray = NULL; - } + s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_pending == NULL) { + IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); + return -ENOMEM; + } + s->sg_pending_size = 0; + + s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_processing == NULL) { + IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + return -ENOMEM; + } + s->sg_processing_size = 0; + + s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + if (s->sg_dma == NULL) { + IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + kfree(s->sg_processing); + s->sg_processing = NULL; return -ENOMEM; } - s->SG_length = 0; if (ivtv_might_use_dma(s)) { - s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); + s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma); ivtv_stream_sync_for_cpu(s); } @@ -272,16 +278,19 @@ void ivtv_stream_free(struct ivtv_stream *s) } /* Free SG Array/Lists */ - if (s->SGarray != NULL) { - if (s->SG_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); - s->SG_handle = IVTV_DMA_UNMAPPED; + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { + pci_unmap_single(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; } - kfree(s->SGarray); - kfree(s->PIOarray); - s->PIOarray = NULL; - s->SGarray = NULL; - s->SG_length = 0; + kfree(s->sg_pending); + kfree(s->sg_processing); + kfree(s->sg_dma); + s->sg_pending = NULL; + s->sg_processing = NULL; + s->sg_dma = NULL; + s->sg_pending_size = 0; + s->sg_processing_size = 0; } } diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 2ed8d548255d..14a9f7fe50aa 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -79,13 +79,13 @@ void ivtv_stream_free(struct ivtv_stream *s); static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 0582b9d57c55..d1cc366c2a35 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -154,7 +154,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; - s->SG_handle = IVTV_DMA_UNMAPPED; + s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); ivtv_queue_init(&s->q_dma); From de870b52be9d52c3dad76c9ea7399cb94abcaa1a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 29 Jul 2007 15:22:05 -0300 Subject: [PATCH 099/310] V4L/DVB (6048): ivtv: fix stop stream locking Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index d1cc366c2a35..4272fbc0bc8b 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -751,6 +751,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } + /* ensure these actions are done only once */ + mutex_lock(&itv->serialize_lock); + /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -803,9 +806,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* ensure these global cleanup actions are done only once */ - mutex_lock(&itv->serialize_lock); - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); From 51a99c0428cc6d3a442eef1c9046099c9383d72b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:16:00 -0300 Subject: [PATCH 100/310] V4L/DVB (6049): ivtv: fix VBI reinsertion decoding - Invalid VBI packets should result in an empty VBI frame, not in an zero-sized frame that causes the reader to incorrectly return a 0 (EOF) value. - PIO completion should not reset the sg_pending_size field. - The DMA offset detection code should be ignored for PIO transfers: it somehow messes up the data on the card and is not needed anyway for PIO. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 5 ++--- drivers/media/video/ivtv/ivtv-vbi.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 9695e5356163..7272f1a71dd9 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -165,7 +165,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->sg_pending_size == 0) { + if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); @@ -252,7 +252,7 @@ static void dma_post(struct ivtv_stream *s) /* Sync Buffer */ ivtv_buf_sync_for_cpu(s, buf); - if (x == 0) { + if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) { @@ -591,7 +591,6 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a7282a91bd97..a58c833c2b04 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -163,8 +163,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) linemask[1] = 0xf; p += 4; } else { - /* unknown VBI data stream */ - return 0; + /* unknown VBI data, convert to empty VBI frame */ + linemask[0] = linemask[1] = 0; } for (i = 0; i < 36; i++) { int err = 0; From e17a06badaedba89fad989eed409661c89a22e04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:48:42 -0300 Subject: [PATCH 101/310] V4L/DVB (6050): ivtv: retry/timer improvements - Give up frame after three retries. - When the last capture/decode ends, make sure to delete the dma_timer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 4 ++++ drivers/media/video/ivtv/ivtv-streams.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 7272f1a71dd9..d68853fd60a3 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -494,7 +494,9 @@ static void ivtv_irq_dma_read(struct ivtv *itv) s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. @@ -554,7 +556,9 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 4272fbc0bc8b..2e632014c90d 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -816,6 +816,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Set the following Interrupt mask bits for capture */ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + del_timer(&itv->dma_timer); /* event notification (off) */ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { @@ -873,6 +874,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + del_timer(&itv->dma_timer); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); clear_bit(IVTV_F_S_STREAMING, &s->s_flags); From 8267761881d6bb91c168ba4d629b778cf106c485 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:16:07 -0300 Subject: [PATCH 102/310] V4L/DVB (6051): cx25840: make proper use of SOFT_RESET Whenever the 0x80b register is used the microcontroller should be reset. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 22 ++++++++++----------- drivers/media/video/cx25840/cx25840-core.c | 7 ++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f93b5160bb4f..3d46a776df36 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -157,13 +157,12 @@ void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); + /* assert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x01); + /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); - /* assert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x01); - /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); @@ -181,15 +180,14 @@ void cx25840_audio_set_path(struct i2c_client *client) set_audclk_freq(client, state->audclk_freq); - /* deassert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x00); - if (state->aud_input != CX25840_AUDIO_SERIAL) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } + + /* deassert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x00); } static int get_volume(struct i2c_client *client) @@ -330,18 +328,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 1); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0); cx25840_write(client, 0x8d3, 0x1f); } - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 1); retval = set_audclk_freq(client, *(u32 *)arg); - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0x10); } + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 0); return retval; case VIDIOC_G_CTRL: diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8f9c32613b45..ae90d1c3d12b 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -250,6 +250,7 @@ static void input_change(struct i2c_client *client) } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); + cx25840_and_or(client, 0x810, ~0x01, 1); if (state->radio) { cx25840_write(client, 0x808, 0xf9); @@ -284,11 +285,7 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } - if (cx25840_read(client, 0x803) & 0x10) { - /* restart audio decoder microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } + cx25840_and_or(client, 0x810, ~0x01, 0); } static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, From 2ce55b606b29c6ab0c8583772f6807b49cc89372 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:09:37 -0300 Subject: [PATCH 103/310] V4L/DVB (6053): ivtv: setup TV output standard on init to prevent flicker The TV output standard was set only on first use, which meant that the saa7127 was set to NTSC until then, leading to flickering on PAL systems. Since the saa7127 has no firmware it is OK to initialize it immediately. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 198e443e8a5e..8086c62e7545 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1145,6 +1145,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, are not. */ itv->tuner_std = itv->std; + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); + } + retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); From 313e91e824c0c595dec3740c0c87f55eea6bdb3f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:32:33 -0300 Subject: [PATCH 104/310] V4L/DVB (6054): ivtv: specify some stream sizes in kB instead of MB Some streams (PCM, VBI decoding) do not need that much memory, so specify the allocated memory in kB instead of MB to limit memory usage. E.g. 1 MB is overkill for the VBI decoding stream, 64 kB is enough. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 +++++++++--------- drivers/media/video/ivtv/ivtv-driver.h | 8 +++++--- drivers/media/video/ivtv/ivtv-streams.c | 14 +++++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 8086c62e7545..3591518ed358 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -208,7 +208,7 @@ MODULE_PARM_DESC(enc_vbi_buffers, "Encoder VBI Buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); MODULE_PARM_DESC(dec_mpg_buffers, "Decoder MPG buffers (in MB)\n" @@ -217,7 +217,7 @@ MODULE_PARM_DESC(dec_yuv_buffers, "Decoder YUV buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in MB)\n" + "Decoder VBI buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); MODULE_PARM_DESC(newi2c, "Use new I2C implementation\n" @@ -547,13 +547,13 @@ static void ivtv_process_options(struct ivtv *itv) const char *chipname; int i, j; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; itv->options.cardtype = cardtype[itv->num]; itv->options.tuner = tuner[itv->num]; itv->options.radio = radio[itv->num]; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index e80f9f65a905..783fb4449b0e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -186,10 +186,12 @@ extern const u32 yuv_offset[4]; #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 /* ======================================================================== */ /* ========================== END USER SETTABLE DMA VARIABLES ============= */ @@ -321,7 +323,7 @@ extern int ivtv_debug; struct ivtv_options { - int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ + int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ int tuner; /* set tuner on load */ int radio; /* enable/disable radio */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 2e632014c90d..fab5c51b1519 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -150,7 +150,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; if (s->buf_size) - s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; + s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; @@ -192,7 +192,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.megabytes[type] == 0) { + itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; } @@ -238,18 +238,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d MB)\n", - s->v4l2dev->minor, s->name, itv->options.megabytes[type]); + IVTV_INFO("Registered device video%d for %s (%d kB)\n", + s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: IVTV_INFO("Registered device radio%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); break; case VFL_TYPE_VBI: - if (itv->options.megabytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", + if (itv->options.kilobytes[type]) + IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, - s->name, itv->options.megabytes[type]); + s->name, itv->options.kilobytes[type]); else IVTV_INFO("Registered device vbi%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); From 1aa32c2ffd146dddd76babf842e998502f1b993a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 06:08:58 -0300 Subject: [PATCH 105/310] V4L/DVB (6055): ivtv: improve debug messages - add FILE debug flag for open/close/read/write/poll. - show cmd for encoder/decoder command ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 ++++++-- drivers/media/video/ivtv/ivtv-driver.h | 55 +++++++++++++------------ drivers/media/video/ivtv/ivtv-fileops.c | 18 ++++---- drivers/media/video/ivtv/ivtv-ioctl.c | 9 +++- drivers/media/video/ivtv/ivtv-mailbox.c | 6 +-- 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 3591518ed358..93ddea49f0ed 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -186,8 +186,18 @@ MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 1023 gives full debugging)"); + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: ioctl\n" + "\t\t\t 16/0x0010: file\n" + "\t\t\t 32/0x0020: dma\n" + "\t\t\t 64/0x0040: irq\n" + "\t\t\t 128/0x0080: decoder\n" + "\t\t\t 256/0x0100: yuv\n" + "\t\t\t 512/0x0200: i2c\n" + "\t\t\t1024/0x0400: high volume\n"); MODULE_PARM_DESC(ivtv_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); @@ -1354,9 +1364,9 @@ static int module_start(void) return -1; } - if (ivtv_debug < 0 || ivtv_debug > 1023) { + if (ivtv_debug < 0 || ivtv_debug > 2047) { ivtv_debug = 0; - printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n"); + printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); } if (pci_register_driver(&ivtv_pci_driver)) { diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 783fb4449b0e..93a008409f49 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -256,17 +256,18 @@ extern const u32 yuv_offset[4]; /* debugging */ -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_API (1 << 2) -#define IVTV_DBGFLG_DMA (1 << 3) -#define IVTV_DBGFLG_IOCTL (1 << 4) -#define IVTV_DBGFLG_I2C (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_WARN (1 << 0) +#define IVTV_DBGFLG_INFO (1 << 1) +#define IVTV_DBGFLG_MB (1 << 2) +#define IVTV_DBGFLG_IOCTL (1 << 3) +#define IVTV_DBGFLG_FILE (1 << 4) +#define IVTV_DBGFLG_DMA (1 << 5) +#define IVTV_DBGFLG_IRQ (1 << 6) +#define IVTV_DBGFLG_DEC (1 << 7) +#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_I2C (1 << 9) /* Flag to turn on high volume debugging */ -#define IVTV_DBGFLG_HIGHVOL (1 << 9) +#define IVTV_DBGFLG_HIGHVOL (1 << 10) /* NOTE: extra space before comma in 'itv->num , ## args' is required for gcc-2.95, otherwise it won't compile. */ @@ -275,30 +276,32 @@ extern const u32 yuv_offset[4]; if ((x) & ivtv_debug) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ do { \ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 076b0089a2b0..846e9bfa41f0 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -409,7 +409,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; struct ivtv *itv = s->itv; - IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc); + IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) pos += rc; return rc; @@ -500,7 +500,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ struct ivtv_stream *s = &itv->streams[id->type]; int rc; - IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); rc = ivtv_start_capture(id); if (rc) @@ -538,7 +538,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c int rc; DEFINE_WAIT(wait); - IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); if (s->type != IVTV_DEC_STREAM_TYPE_MPG && s->type != IVTV_DEC_STREAM_TYPE_YUV && @@ -646,7 +646,7 @@ retry: to transfer the rest. */ if (count && !(filp->f_flags & O_NONBLOCK)) goto retry; - IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); return bytes_written; } @@ -658,6 +658,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) int res = 0; /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Decoder poll\n"); poll_wait(filp, &s->waitq, wait); set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); @@ -687,9 +688,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) s->name, rc); return POLLERR; } + IVTV_DEBUG_FILE("Encoder poll started capture\n"); } /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); if (eof || s->q_full.length) @@ -702,7 +705,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* 'Unclaim' this stream */ @@ -740,7 +743,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -772,7 +775,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close %s\n", s->name); v4l2_prio_close(&itv->prio, &id->prio); @@ -855,6 +858,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } + IVTV_DEBUG_FILE("open %s\n", s->name); if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 734f2d2ffa62..2c0f27241332 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1138,12 +1138,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void memset(&enc->raw, 0, sizeof(enc->raw)); switch (enc->cmd) { case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); enc->flags = 0; if (try) return 0; return ivtv_start_capture(id); case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; if (try) return 0; @@ -1151,6 +1153,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return 0; case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); enc->flags = 0; if (try) return 0; @@ -1163,6 +1166,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); enc->flags = 0; if (try) return 0; @@ -1174,6 +1178,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_unmute(itv); break; default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } break; @@ -1408,9 +1413,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) int try = (cmd == VIDEO_TRY_COMMAND); if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); return ivtv_video_command(itv, id, vc, try); } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c index 5e3b679202ae..b05436da7136 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/drivers/media/video/ivtv/ivtv-mailbox.c @@ -225,15 +225,15 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) } if (args < 0 || args > CX2341X_MBOX_MAX_DATA || cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); + IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); return -EINVAL; } if (api_info[cmd].flags & API_HIGH_VOL) { - IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); } else { - IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); } /* clear possibly uninitialized part of data array */ From baa4072d84e7a2e9954121c826d7bb8f1fb66b38 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:10:55 -0300 Subject: [PATCH 106/310] V4L/DVB (6056): ivtv: move serialization to the fileops level Serialization is now done on the open/close/ioctl level and also when the read/write/poll start an encoder/decoder stream. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 95 +++++++++++++++---------- drivers/media/video/ivtv/ivtv-ioctl.c | 26 +++++-- drivers/media/video/ivtv/ivtv-streams.c | 11 --- 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 846e9bfa41f0..1f3c8d0310f5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -502,7 +502,9 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) return rc; return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); @@ -613,7 +615,9 @@ retry: } /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); @@ -681,8 +685,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc = ivtv_start_capture(id); + int rc; + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", s->name, rc); @@ -788,6 +795,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) /* 'Unclaim' this stream */ /* Stop radio */ + mutex_lock(&itv->serialize_lock); if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { /* Closing radio device, return to TV mode */ ivtv_mute(itv); @@ -822,53 +830,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_capture(id, 0); } kfree(id); + mutex_unlock(&itv->serialize_lock); return 0; } -int ivtv_v4l2_open(struct inode *inode, struct file *filp) +static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) { - int x, y = 0; + struct ivtv *itv = s->itv; struct ivtv_open_id *item; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - int minor = iminor(inode); - /* Find which card this open was on */ - spin_lock(&ivtv_cards_lock); - for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { - /* find out which stream this open was on */ - for (y = 0; y < IVTV_MAX_STREAMS; y++) { - s = &ivtv_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { - itv = ivtv_cards[x]; - break; - } - } - } - spin_unlock(&ivtv_cards_lock); - - if (itv == NULL) { - /* Couldn't find a device registered - on that minor, shouldn't happen! */ - IVTV_WARN("No ivtv device found on minor %d\n", minor); - return -ENXIO; - } - - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on minor %d\n", minor); - return -ENXIO; - } IVTV_DEBUG_FILE("open %s\n", s->name); - if (y == IVTV_DEC_STREAM_TYPE_MPG && + if (s->type == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV && + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { if (read_reg(0x82c) == 0) { IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); /* return -ENODEV; */ @@ -883,7 +864,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENOMEM; } item->itv = itv; - item->type = y; + item->type = s->type; v4l2_prio_open(&itv->prio, &item->prio); item->open_id = itv->open_id++; @@ -925,14 +906,50 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (y == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (y == IVTV_DEC_STREAM_TYPE_YUV) - { + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + return 0; +} + +int ivtv_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct ivtv *itv = NULL; + struct ivtv_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&ivtv_cards_lock); + for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < IVTV_MAX_STREAMS; y++) { + s = &ivtv_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + itv = ivtv_cards[x]; + break; + } + } + } + spin_unlock(&ivtv_cards_lock); + + if (itv == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + IVTV_WARN("No ivtv device found on minor %d\n", minor); + return -ENXIO; } - return 0; + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&itv->serialize_lock); + return -ENXIO; + } + res = ivtv_serialized_open(s, filp); + mutex_unlock(&itv->serialize_lock); + return res; } void ivtv_mute(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2c0f27241332..2061d82653fc 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1446,11 +1446,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; if (nonblocking) return -EAGAIN; - /* wait for event */ + /* Wait for event. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) schedule(); finish_wait(&itv->event_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { /* return if a signal was received */ IVTV_DEBUG_INFO("User stopped wait for event\n"); @@ -1580,12 +1584,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, return 0; } -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - /* Filter dvb ioctls that cannot be handled by video_usercopy */ switch (cmd) { case VIDEO_SELECT_SOURCE: @@ -1620,3 +1621,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); } + +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv *itv = id->itv; + int res; + + mutex_lock(&itv->serialize_lock); + res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg); + mutex_unlock(&itv->serialize_lock); + return res; +} diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fab5c51b1519..65fa247e33c5 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (s->v4l2dev == NULL) return -EINVAL; - /* Big serialization lock to ensure no two streams are started - simultaneously: that can give all sorts of weird results. */ - mutex_lock(&itv->serialize_lock); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { @@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) 0, sizeof(itv->vbi.sliced_mpeg_size)); break; default: - mutex_unlock(&itv->serialize_lock); return -EINVAL; } s->subtype = subtype; @@ -564,7 +560,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) { IVTV_DEBUG_WARN( "Error starting capture!\n"); - mutex_unlock(&itv->serialize_lock); return -EINVAL; } @@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* you're live! sit back and await interrupts :) */ atomic_inc(&itv->capturing); - mutex_unlock(&itv->serialize_lock); return 0; } @@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } - /* ensure these actions are done only once */ - mutex_lock(&itv->serialize_lock); - /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -810,7 +801,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); if (atomic_read(&itv->capturing) > 0) { - mutex_unlock(&itv->serialize_lock); return 0; } @@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } wake_up(&s->waitq); - mutex_unlock(&itv->serialize_lock); return 0; } From 3869c6a088c2eb165abe476c3372c6a3653649b3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:11:44 -0300 Subject: [PATCH 107/310] V4L/DVB (6057): ivtv-fb: remove unused header includes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index d2cc03172749..008076543aca 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -57,12 +57,8 @@ #endif #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-fileops.h" #include "ivtv-mailbox.h" -#include "ivtv-cards.h" #include /* card parameters */ From 0989fd2c88a11aa5014b2b348ed51872d14d536d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 12:25:39 -0300 Subject: [PATCH 108/310] V4L/DVB (6058): ivtv: add support for highmem udma When trying to DMA userspace buffers to the cx23415 you need to check whether the page is in highmem. If this is the case, then bounce buffers have to be used to allow DMA. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 ++ drivers/media/video/ivtv/ivtv-udma.c | 45 +++++++++++++++++++++----- drivers/media/video/ivtv/ivtv-yuv.c | 9 +++++- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 93a008409f49..784098d4bf04 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -419,6 +419,8 @@ struct ivtv_user_dma { struct mutex lock; int page_count; struct page *map[IVTV_DMA_SG_OSD_ENT]; + /* Needed when dealing with highmem userspace buffers */ + struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index bd642e1aafc3..5592abbe14e6 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -38,23 +38,38 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) { int i, offset; + unsigned long flags; offset = dma_page->offset; /* Fill SG Array with new values */ for (i = 0; i < dma_page->page_count; i++) { - if (i == dma_page->page_count - 1) { - dma->SGlist[map_offset].length = dma_page->tail; + unsigned int len = (i == dma_page->page_count - 1) ? + dma_page->tail : PAGE_SIZE - offset; + + dma->SGlist[map_offset].length = len; + dma->SGlist[map_offset].offset = offset; + if (PageHighMem(dma->map[map_offset])) { + void *src; + + if (dma->bouncemap[map_offset] == NULL) + dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); + if (dma->bouncemap[map_offset] == NULL) + return -ENOMEM; + local_irq_save(flags); + src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); + kunmap_atomic(src, KM_BOUNCE_READ); + local_irq_restore(flags); + dma->SGlist[map_offset].page = dma->bouncemap[map_offset]; } else { - dma->SGlist[map_offset].length = PAGE_SIZE - offset; + dma->SGlist[map_offset].page = dma->map[map_offset]; } - dma->SGlist[map_offset].offset = offset; - dma->SGlist[map_offset].page = dma->map[map_offset]; offset = 0; map_offset++; } - return map_offset; + return 0; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, { struct ivtv_dma_page_info user_dma; struct ivtv_user_dma *dma = &itv->udma; - int err; + int i, err; IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); @@ -123,7 +138,14 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - ivtv_udma_fill_sg_list(dma, &user_dma, 0); + err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); + if (err) { + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return err; + } /* Map SG List */ dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); @@ -166,6 +188,8 @@ void ivtv_udma_unmap(struct ivtv *itv) void ivtv_udma_free(struct ivtv *itv) { + int i; + /* Unmap SG Array */ if (itv->udma.SG_handle) { pci_unmap_single(itv->dev, itv->udma.SG_handle, @@ -176,6 +200,11 @@ void ivtv_udma_free(struct ivtv *itv) if (itv->udma.SG_length) { pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { + if (itv->udma.bouncemap[i]) + __free_page(itv->udma.bouncemap[i]); + } } void ivtv_udma_start(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index fa8c76f3d359..2ae7556f5e68 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ From 25e3f8f40ecf61b87a4b6476ea6d00cb5b74628c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 15:03:05 -0300 Subject: [PATCH 109/310] V4L/DVB (6059): ivtv: log stereo/bilingual audio modes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2061d82653fc..de866d450ecd 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1235,7 +1235,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s\n", audin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; @@ -1247,11 +1248,20 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "YUV Frames", "Passthrough", }; + static const char * const audio_modes[] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s\n", audout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); From 8beb058f1ecde7bc0554d18ce1baa18b5dfb02d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 17:56:41 -0300 Subject: [PATCH 110/310] V4L/DVB (6060): ivtv: fix IVTV_IOC_DMA_FRAME bug introduced by highmem bugfix The return value of ivtv_udma_fill_sg_list() was changed by the highmem bugfix, but that return value was still used in ivtv-yuv.c. Revert to the old return value, but in addition return -1 in case of a memory allocation error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-udma.c | 12 +++++++----- drivers/media/video/ivtv/ivtv-yuv.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 5592abbe14e6..7e503adacea0 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -40,6 +40,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info int i, offset; unsigned long flags; + if (map_offset < 0) + return map_offset; + offset = dma_page->offset; /* Fill SG Array with new values */ @@ -55,7 +58,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info if (dma->bouncemap[map_offset] == NULL) dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); if (dma->bouncemap[map_offset] == NULL) - return -ENOMEM; + return -1; local_irq_save(flags); src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); @@ -69,7 +72,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info offset = 0; map_offset++; } - return 0; + return map_offset; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -138,13 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); - if (err) { + if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); } dma->page_count = 0; - return err; + return -ENOMEM; } /* Map SG List */ diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 2ae7556f5e68..1922c1da20d3 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); From 7c03a4488bf6d28078488c70c82357d4286cacc5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 18:59:42 -0300 Subject: [PATCH 111/310] V4L/DVB (6061): ivtv: add VIDIOC_OVERLAY Add VIDIOC_OVERLAY to enable/disable the OSD. Also add the OSD state to the log status report. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 45 +++++++++++++++++++++---- drivers/media/video/ivtv/ivtv-streams.c | 6 ++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index de866d450ecd..ed5707660e0e 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1217,9 +1217,19 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; } + case VIDIOC_OVERLAY: { + int *on = arg; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); + break; + } + case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1234,8 +1244,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; @@ -1255,6 +1265,22 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Mono", "Swapped" }; + static const char * const alpha_mode[] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[] = { + "Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); @@ -1264,12 +1290,17 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0x7]); } - IVTV_INFO("Tuner: %s\n", + IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; @@ -1279,7 +1310,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void (s->buffers - s->q_free.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } - IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); break; } @@ -1501,6 +1532,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_S_AUDOUT: case VIDIOC_S_EXT_CTRLS: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: ret = v4l2_prio_check(&itv->prio, &id->prio); if (ret) return ret; @@ -1554,6 +1586,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_TRY_ENCODER_CMD: case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 65fa247e33c5..ebf925c549fd 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -75,7 +75,7 @@ static struct { struct file_operations *fops; } ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", + "encoder MPG", VFL_TYPE_GRABBER, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops @@ -93,7 +93,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", + "encoder PCM", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops @@ -105,7 +105,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPEG", + "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops From 8ddac9ee4b6f08d7cacf79202ab882eefc55b0c0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 06:57:55 -0300 Subject: [PATCH 112/310] V4L/DVB (6064): cx88: Add symbolic names for the PCI interrupt bits Used for the PCI_INTMSK and PCI_INT_STAT registers. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 16 +++++++++------- drivers/media/video/cx88/cx88-cards.c | 4 +++- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-mpeg.c | 9 +++++---- drivers/media/video/cx88/cx88-reg.h | 22 ++++++++++++++++++++++ drivers/media/video/cx88/cx88-vbi.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 9 +++++---- 8 files changed, 49 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 2d666b56020c..a529c0a87d1a 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -149,9 +149,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); - dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02)); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", + chip->core->pci_irqmask, + chip->core->pci_irqmask | PCI_INT_AUDINT); /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02); + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* Enables corresponding bits at AUD_INT_STAT */ @@ -184,7 +186,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) cx_clear(MO_AUD_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); cx_clear(MO_AUD_INTMSK, (1<<16)| (1<<12)| @@ -273,7 +275,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; dprintk( 3, "cx8801_irq\n" ); @@ -282,8 +285,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & 0x02) - { + if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); } @@ -293,7 +295,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) dprintk( 0, "clearing mask\n" ); dprintk(1,"%s/0: irq loop -- clearing mask\n", core->name); - cx_clear(MO_PCI_INTMSK,0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } out: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e73e8c96d5b9..a4eb6a87a761 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2063,7 +2063,9 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; + core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | + PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | + PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; mutex_init(&core->lock); core->nr = nr; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 0765e9db5339..970926b97ee4 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -498,7 +498,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status) { int handled = 0; - if (status & (1<<18)) { + if (status & PCI_INT_IR_SMPINT) { cx88_ir_irq(core); handled++; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 120f56857f0e..c78a95ef7581 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -167,7 +167,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) schedule_work(&ir->work); } if (ir->sampling) { - core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + core->pci_irqmask |= PCI_INT_IR_SMPINT; cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ cx_write(MO_DDSCFG_IO, 0x5); /* enable */ } @@ -177,7 +177,7 @@ static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); - core->pci_irqmask &= ~(1 << 18); + core->pci_irqmask &= ~PCI_INT_IR_SMPINT; } if (ir->polling) { diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 5da47e251e66..d46114685ed1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -148,7 +148,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); cx_set(MO_TS_INTMSK, 0x1f0011); /* start dma */ @@ -166,7 +166,7 @@ static int cx8802_stop_dma(struct cx8802_dev *dev) cx_clear(MO_TS_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000004); + cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT); cx_clear(MO_TS_INTMSK, 0x1f0011); /* Reset the controller */ @@ -413,7 +413,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_TSINT); if (0 == status) goto out; dprintk( 1, "cx8802_irq\n" ); @@ -424,7 +425,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x04) + if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); }; if (MAX_IRQ_LOOP == loop) { diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index d3bf5b17b1d4..2b1d102cd220 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -582,6 +582,28 @@ /* ---------------------------------------------------------------------- */ /* various constants */ +// DMA +/* Interrupt mask/status */ +#define PCI_INT_VIDINT (1 << 0) +#define PCI_INT_AUDINT (1 << 1) +#define PCI_INT_TSINT (1 << 2) +#define PCI_INT_VIPINT (1 << 3) +#define PCI_INT_HSTINT (1 << 4) +#define PCI_INT_TM1INT (1 << 5) +#define PCI_INT_SRCDMAINT (1 << 6) +#define PCI_INT_DSTDMAINT (1 << 7) +#define PCI_INT_RISC_RD_BERRINT (1 << 10) +#define PCI_INT_RISC_WR_BERRINT (1 << 11) +#define PCI_INT_BRDG_BERRINT (1 << 12) +#define PCI_INT_SRC_DMA_BERRINT (1 << 13) +#define PCI_INT_DST_DMA_BERRINT (1 << 14) +#define PCI_INT_IPB_DMA_BERRINT (1 << 15) +#define PCI_INT_I2CDONE (1 << 16) +#define PCI_INT_I2CRACK (1 << 17) +#define PCI_INT_IR_SMPINT (1 << 18) +#define PCI_INT_GPIO_INT0 (1 << 19) +#define PCI_INT_GPIO_INT1 (1 << 20) + #define SEL_BTSC 0x01 #define SEL_EIAJ 0x02 #define SEL_A2 0x04 diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 86c1cf8334bc..16c0d36bb6b2 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -67,7 +67,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ @@ -91,7 +91,7 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x18); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0088); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e158ea2454af..e96c688cba9f 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -423,7 +423,7 @@ static int start_video_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); /* Enables corresponding bits at PCI_INT_STAT: bits 0 to 4: video, audio, transport stream, VIP, Host @@ -456,7 +456,7 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x06); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0011); return 0; } @@ -1604,7 +1604,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_VIDINT); if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); @@ -1612,7 +1613,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x01) + if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); }; if (10 == loop) { From 5ba862b77e2d7f9e6e2cb133c43be32ac612aea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 07:02:26 -0300 Subject: [PATCH 113/310] V4L/DVB (6065): cx88-alsa: Call core irq handler when needed When an irq handled by the cx88 core driver (currently IR and errors) occurs and the cx88-alsa irq handler is the first called, it will claim to have handled the irq but it doesn't call cx88_core_irq() to handle it. The means loading cx88-alsa can disable the IR remote. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index a529c0a87d1a..76a8c01208c1 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -285,6 +285,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); + if (status & core->pci_irqmask) + cx88_core_irq(core, status); if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); From 59fd8f8d8ee9f7539758419965381bcccfa6f798 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:09:42 -0300 Subject: [PATCH 114/310] V4L/DVB (6066): cx88-alsa: Change order of interrupt enabling, fix spurious IRQs Currently the driver turns on audio interrupts, then sets the audio interrupt mask to select which interrupts to get. One could received unwanted interrupts since the mask is set _after_ interrupts have already been turned on. Change the order of the operations, and clear any audio interrupt status bits that are already set for good measure. Before changing the SRAM FIFO parameters, make sure the FIFO isn't being used. This shouldn't happen with just the ALSA driver, as it should never try to turn on FIFO/RISC/DMA while they are already on. However, the V4L driver needs to turn the audio FIFO on for analog audio output to work (undocumented cx88 bug). The FIFO parameters are in an inconsistent state while they are updated, and this results in many FIFO sync error IRQs if the FIFO is in use while it's in this inconsistent state. Also create and use a bunch of symbolic constants for audio interrupt mask bits. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 42 +++++++++++++--------------- drivers/media/video/cx88/cx88-reg.h | 13 +++++++++ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 76a8c01208c1..ecb9a74ae03d 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -136,12 +136,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) struct cx88_core *core=chip->core; struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; - - dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start); + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(MO_AUD_DMACNTRL, 0x11); /* setup fifo + format - out channel */ - cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25], - buf->bpl, buf->risc.dma); + cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma); /* sets bpl size */ cx_write(MO_AUDD_LNGTH, buf->bpl); @@ -149,27 +148,30 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " + "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", chip->core->pci_irqmask, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + /* Clean any pending interrupt bits already set */ + cx_write(MO_AUD_INTSTAT, ~0); + + /* enable audio irqs */ + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ if (debug) - cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + cx88_sram_channel_dump(chip->core, audio_ch); return 0; } @@ -187,12 +189,8 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); - cx_clear(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); if (debug) cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); @@ -239,14 +237,14 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), status, mask); /* risc op code error */ - if (status & (1 << 16)) { + if (status & AUD_INT_OPC_ERR) { printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } /* risc1 downstream */ - if (status & 0x01) { + if (status & AUD_INT_DN_RISCI1) { spin_lock(&chip->reg_lock); count = cx_read(MO_AUDD_GPCNT); spin_unlock(&chip->reg_lock); diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 2b1d102cd220..2ec52d1cdea0 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -612,6 +612,19 @@ #define SEL_FMRADIO 0x20 // AUD_CTL +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) + #define EN_BTSC_FORCE_MONO 0 #define EN_BTSC_FORCE_STEREO 1 #define EN_BTSC_FORCE_SAP 2 From 5a5b3b5d4fe3acdd9fb73162023422a9ee0e56f3 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 21:01:40 -0300 Subject: [PATCH 115/310] V4L/DVB (6067): cx88-alsa: Hardware doesn't support mono audio channels_min should be 2, not 1. The hardware only supports stereo. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ecb9a74ae03d..3e293da0f70b 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -335,7 +335,7 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (2*2048), .period_bytes_min = 2048, From 19453bc18848e842a9743fcc40707e6fb19ae92b Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:54:49 -0300 Subject: [PATCH 116/310] V4L/DVB (6068): cx88-alsa: Use pci_dev->revision The revision is part of the pci_dev struct, so there is no need to read it in. Stop storing the revision and latency in the chip struct, since they're never used after being printed out when the driver loads. linux/pci.h wasn't included. It was getting picked up something else, probably cx88.h, but this file uses struct pci_dev so it should include pci.h. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 3e293da0f70b..8d19d33c8b32 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -60,7 +61,6 @@ struct cx88_audio_dev { /* pci i/o */ struct pci_dev *pci; - unsigned char pci_rev,pci_lat; /* audio controls */ int irq; @@ -667,6 +667,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, snd_cx88_card_t *chip; struct cx88_core *core; int err; + unsigned char pci_lat; *rchip = NULL; @@ -711,13 +712,12 @@ static int __devinit snd_cx88_create(struct snd_card *card, } /* print pci info */ - pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev); - pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat); + pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%llx\n", core->name, devno, - pci_name(pci), chip->pci_rev, pci->irq, - chip->pci_lat,(unsigned long long)pci_resource_start(pci,0)); + pci_name(pci), pci->revision, pci->irq, + pci_lat, (unsigned long long)pci_resource_start(pci,0)); chip->irq = pci->irq; synchronize_irq(chip->irq); From 261f5081a4dbcd148be0a0e744fb454a4f688441 Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:06:00 -0300 Subject: [PATCH 117/310] V4L/DVB (6071): saa7134-dvb: add missing newline This is a simple whitespace cleanup. Signed-off-by: Edgar Simo Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1f6bd3300715..a0ce67ecb018 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -567,6 +567,7 @@ static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config } /* ------------------------------------------------------------------ */ + static struct tda1004x_config tda827x_lifeview_config = { .demod_address = 0x08, .invert = 1, @@ -746,6 +747,7 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = { .antenna_switch= 2, .request_firmware = philips_tda1004x_request_firmware }; + static struct tda1004x_config kworld_dvb_t_210_config = { .demod_address = 0x08, .invert = 1, @@ -760,6 +762,7 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .antenna_switch= 1, .request_firmware = philips_tda1004x_request_firmware }; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ From d90d9f5a0ae9eb80bb3a33472074a114af7e548d Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:14:50 -0300 Subject: [PATCH 118/310] V4L/DVB (6072): saa7134: add DVB-T support for Avermedia Super 007 Add DVB-T support for Avermedia Super 007 Analog television is untested. The device lacks input adapters for radio, svideo & composite -- seems to be a DVB-T ONLY device. Signed-off-by: Edgar Simo Acked-by: Hermann Pitton Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 23 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 18 ++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 43 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 3f8aeab50a10..831b4da48b80 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -115,3 +115,4 @@ 114 -> KWorld DVB-T 210 [17de:7250] 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] +117 -> Avermedia Super 007 [1461:f01d] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 25ec16810818..5c3174a62e58 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3534,6 +3534,22 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x3000, }, }, + [SAA7134_BOARD_AVERMEDIA_SUPER_007] = { + .name = "Avermedia Super 007", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, /* FIXME: analog tv untested */ + .vmux = 1, + .amux = TV, + .tv = 1, + }}, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4256,6 +4272,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2304, .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ + .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4564,6 +4586,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index a0ce67ecb018..bbab252cbeee 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -763,6 +763,21 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .request_firmware = philips_tda1004x_request_firmware }; +static struct tda1004x_config avermedia_super_007_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GP01_I, + .if_freq = TDA10046_FREQ_045, + .i2c_gate = 0x4b, + .tuner_address = 0x60, + .tuner_config = 0, + .antenna_switch= 1, + .request_firmware = philips_tda1004x_request_firmware +}; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ @@ -1025,6 +1040,9 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); break; + case SAA7134_BOARD_AVERMEDIA_SUPER_007: + configure_tda827x_fe(dev, &avermedia_super_007_config); + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 346255468dad..fd12942b3a10 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -239,6 +239,7 @@ struct saa7134_format { #define SAA7134_BOARD_KWORLD_DVBT_210 114 #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 +#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 From c996899d0bc2414c7ff4682500344eb912d5ee1d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 20 Aug 2007 21:04:44 -0300 Subject: [PATCH 119/310] V4L/DVB (6074): tuner: fix ifdef tags to match actual file name The file, tuner-driver.h was originally named tuner-hw.h, but we decided to rename it. At the time, I had forgotten to change the #ifdef __TUNER_HW_H__ to #ifdef __TUNER_DRIVER_H__ . This patch corrects that. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index fa51b7cec691..145045561a51 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -19,8 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __TUNER_HW_H__ -#define __TUNER_HW_H__ +#ifndef __TUNER_DRIVER_H__ +#define __TUNER_DRIVER_H__ #include #include @@ -95,7 +95,7 @@ extern int tea5767_tuner_init(struct i2c_client *c); printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#endif /* __TUNER_HW_H__ */ +#endif /* __TUNER_DRIVER_H__ */ /* * Overrides for Emacs so that we follow Linus's tabbing style. From ffbb807c1362a2b64b473c0e093c496a4c7de4bb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:14:12 -0300 Subject: [PATCH 120/310] V4L/DVB (6075): tuner: kernel headers go above subsystem headers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 2 +- drivers/media/video/tda8290.c | 2 +- drivers/media/video/tda9887.c | 3 +-- drivers/media/video/tea5761.c | 2 +- drivers/media/video/tea5767.c | 2 +- drivers/media/video/tuner-core.c | 3 +-- drivers/media/video/tuner-simple.c | 1 + 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 7549114aaaca..210a84d8b971 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,8 +5,8 @@ */ #include #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 59cff5a3c59e..760d22f65da2 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -19,8 +19,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index aa311e4f1f61..e8597c10aa4c 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -3,12 +3,11 @@ #include #include #include -#include #include #include #include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index ae105c2cd0ac..43bdc374927e 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -8,8 +8,8 @@ */ #include -#include #include +#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4985d47a508f..4c9c4e01331a 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" #define PREFIX "TEA5767 " diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e646465464a1..5f378265d8c5 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -15,9 +15,8 @@ #include #include #include -#include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b98..f1ee60a4aa76 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include From 5634f2ec809818983f58880e381ee929187e4ddf Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:36 -0300 Subject: [PATCH 121/310] V4L/DVB (6076): Coding style fix drivers/media/video/zr36060.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36060.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c index 97c8f9b9dc12..1ef14fef08e6 100644 --- a/drivers/media/video/zr36060.c +++ b/drivers/media/video/zr36060.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36060.h" +#include "zr36060.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ From b9758dfe0a2065f6fe3a484cc26886960aa847c1 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:48 -0300 Subject: [PATCH 122/310] V4L/DVB (6077): Coding style fix drivers/media/video/zr36050.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36050.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c index a6bbd125631c..9f622e00c479 100644 --- a/drivers/media/video/zr36050.c +++ b/drivers/media/video/zr36050.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36050.h" +#include "zr36050.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ From f518b43c452fb2dbe98ee211abfc63cf421927ab Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:36:51 -0300 Subject: [PATCH 123/310] V4L/DVB (6078): Coding style fix drivers/media/video/zr36016.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36016.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c index 62f77584fb85..dd084555da8f 100644 --- a/drivers/media/video/zr36016.c +++ b/drivers/media/video/zr36016.c @@ -38,11 +38,11 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* v4l API */ -#include +#include /* headerfile of this module */ #include"zr36016.h" From 9c12224a607a4b22ab86784e3394b52810b9507c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 21 Aug 2007 12:38:39 -0300 Subject: [PATCH 124/310] V4L/DVB (6079): Cleanup: remove linux/moduleparam.h from drivers/media files Since at least kernel 2.6.12-rc2, module.h includes moduleparm.h. This patch removes all occurences of moduleparm.h from drivers/media files. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-functions.c | 1 - drivers/media/common/ir-keymaps.c | 1 - drivers/media/dvb/bt8xx/bt878.c | 1 - drivers/media/dvb/bt8xx/dvb-bt8xx.c | 1 - drivers/media/dvb/dvb-core/dmxdev.c | 1 - drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 1 - drivers/media/dvb/dvb-core/dvb_frontend.c | 1 - drivers/media/dvb/dvb-core/dvbdev.c | 1 - drivers/media/dvb/frontends/bcm3510.c | 1 - drivers/media/dvb/frontends/cx22700.c | 1 - drivers/media/dvb/frontends/cx24110.c | 1 - drivers/media/dvb/frontends/cx24123.c | 1 - drivers/media/dvb/frontends/dib3000mb.c | 1 - drivers/media/dvb/frontends/dvb_dummy_fe.c | 1 - drivers/media/dvb/frontends/isl6421.c | 1 - drivers/media/dvb/frontends/l64781.c | 1 - drivers/media/dvb/frontends/lgdt330x.c | 1 - drivers/media/dvb/frontends/lnbp21.c | 1 - drivers/media/dvb/frontends/mt2060.c | 1 - drivers/media/dvb/frontends/mt2131.c | 1 - drivers/media/dvb/frontends/mt2266.c | 1 - drivers/media/dvb/frontends/mt312.c | 1 - drivers/media/dvb/frontends/mt352.c | 1 - drivers/media/dvb/frontends/nxt200x.c | 1 - drivers/media/dvb/frontends/or51132.c | 1 - drivers/media/dvb/frontends/or51211.c | 1 - drivers/media/dvb/frontends/sp8870.c | 1 - drivers/media/dvb/frontends/sp887x.c | 1 - drivers/media/dvb/frontends/stv0299.c | 1 - drivers/media/dvb/frontends/tda1004x.c | 1 - drivers/media/dvb/frontends/tda10086.c | 1 - drivers/media/dvb/frontends/tda8083.c | 1 - drivers/media/dvb/frontends/zl10353.c | 1 - drivers/media/dvb/ttpci/av7110.c | 1 - drivers/media/dvb/ttpci/av7110_ir.c | 1 - drivers/media/dvb/ttpci/budget-core.c | 1 - drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 1 - drivers/media/video/bt8xx/bttv-cards.c | 1 - drivers/media/video/bt8xx/bttv-driver.c | 1 - drivers/media/video/bt8xx/bttv-i2c.c | 1 - drivers/media/video/bt8xx/bttv-input.c | 1 - drivers/media/video/bt8xx/bttv-vbi.c | 1 - drivers/media/video/btcx-risc.c | 1 - drivers/media/video/cafe_ccic.c | 1 - drivers/media/video/cpia.c | 1 - drivers/media/video/cpia2/cpia2_v4l.c | 1 - drivers/media/video/cx2341x.c | 1 - drivers/media/video/cx88/cx88-blackbird.c | 1 - drivers/media/video/cx88/cx88-core.c | 1 - drivers/media/video/cx88/cx88-i2c.c | 1 - drivers/media/video/cx88/cx88-input.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-tvaudio.c | 1 - drivers/media/video/cx88/cx88-vbi.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - drivers/media/video/cx88/cx88-vp3054-i2c.c | 1 - drivers/media/video/em28xx/em28xx-core.c | 1 - drivers/media/video/em28xx/em28xx-input.c | 1 - drivers/media/video/et61x251/et61x251_core.c | 1 - drivers/media/video/ir-kbd-i2c.c | 1 - drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/mt20xx.c | 1 - drivers/media/video/ov7670.c | 1 - drivers/media/video/ovcamchip/ovcamchip_core.c | 1 - drivers/media/video/pvrusb2/pvrusb2-main.c | 1 - drivers/media/video/pwc/pwc-if.c | 1 - drivers/media/video/saa7134/saa7134-alsa.c | 1 - drivers/media/video/saa7134/saa7134-core.c | 1 - drivers/media/video/saa7134/saa7134-empress.c | 1 - drivers/media/video/saa7134/saa7134-i2c.c | 1 - drivers/media/video/saa7134/saa7134-input.c | 1 - drivers/media/video/saa7134/saa7134-oss.c | 1 - drivers/media/video/saa7134/saa7134-ts.c | 1 - drivers/media/video/saa7134/saa7134-tvaudio.c | 1 - drivers/media/video/saa7134/saa7134-vbi.c | 1 - drivers/media/video/saa7134/saa7134-video.c | 1 - drivers/media/video/sn9c102/sn9c102_core.c | 1 - drivers/media/video/tda9887.c | 1 - drivers/media/video/tuner-core.c | 1 - drivers/media/video/tuner-simple.c | 1 - drivers/media/video/tvaudio.c | 1 - drivers/media/video/tveeprom.c | 1 - drivers/media/video/tvmixer.c | 1 - drivers/media/video/usbvision/usbvision-core.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 1 - drivers/media/video/v4l1-compat.c | 1 - drivers/media/video/video-buf.c | 1 - drivers/media/video/vino.c | 1 - drivers/media/video/w9968cf.c | 1 - drivers/media/video/zc0301/zc0301_core.c | 1 - 91 files changed, 91 deletions(-) diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index a3292e955aaa..e7c3ab951a44 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index cbd1184b5219..137f68bee39f 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -20,7 +20,6 @@ */ #include -#include #include #include diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index df72b4b8ee10..eca602d9b3de 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 67613eb6fa3d..dedd30a8356b 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 5394de2e4ce0..f94bc31e3b33 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 4fadddb264d6..b0bf21958ede 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 1a1b2405b0f4..880d499cd36a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 0f18ce8a9397..6b7954daeb4a 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index baeb311de893..a913f49c062b 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 13ad1bfae663..11a4968f18cb 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 10fc0c8316dd..b03d8283c37d 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 0834c0677fef..d74fdbd63361 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index b6adea5ffeb8..136b9d2164d7 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 6271b1e7f6ab..fed09dfb2b7c 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c index c967148a5945..684c8ec166cb 100644 --- a/drivers/media/dvb/frontends/isl6421.c +++ b/drivers/media/dvb/frontends/isl6421.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 1aeacb1c4af7..443d9045d4c9 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e25286e2d431..bdc9fa88b86a 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 2d2f58c26226..76f935d9755a 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c index 450fad8d9b65..1305b0e63ce5 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/dvb/frontends/mt2060.c @@ -22,7 +22,6 @@ /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 375dfa166817..6bcc4ccc9911 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 33b388e8f7b8..03fe8265745f 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 1ef821825641..0606b9a5b616 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 87e31ca7e108..5dd9b731f6f2 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index ddc84899cf86..fcf964fe1d6b 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 3cc8b444b8f2..b314a1f2deed 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,7 +36,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f46d5a46683a..f02bd9445955 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index d98fd5c2e13e..da876f7bfe32 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 5c2f8f4e0ae5..1aa2539f5099 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 6c607302c1b6..035dd7ba6519 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 33a84372c9e6..8415a8a5247a 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 0f2d4b415560..9a8ddc537f8f 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 0f041e873781..011b74f798a0 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 245f9b7dddfa..a97a7fd2c891 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8178832d14a8..aecfdeb8ec43 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 6322800ee12b..e8f553719bc5 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index b611f2b1f8bc..0252081f013c 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -34,7 +34,6 @@ * the project's page is at http://www.linuxtv.org/dvb/ */ -#include #include "budget.h" #include "ttpci-eeprom.h" diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index b60cdc93d6db..288e79f2cb0f 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 78c98b089975..5e691fd79904 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index f6715007d409..1f4f2625395e 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index cb555f2c40f9..0711c9507843 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 0dfa49b66418..844f1762c45a 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 4201552bc3c0..e7c521b8444a 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 93e35de5a181..007485aa4f01 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index b4aca7249276..ce0840ccd594 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ef5361824f87..0fae0e000f1a 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 78c9699eafbb..a1d02e5ce0fd 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -28,7 +28,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 92778cd1d735..e3aaba1e0e0a 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "cpia2.h" #include "cpia2dev.h" diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index d73c86aeeaac..904bba0dbc4d 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -20,7 +20,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 74e3eb945751..206af419aea7 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 970926b97ee4..cea3212d28b4 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6b42dea860fd..6ae21750b2c1 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c78a95ef7581..78adf4d1cf63 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "cx88.h" #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d46114685ed1..6ece35b5fc83 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 9aee8c51ee27..82364fb07025 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -36,7 +36,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 16c0d36bb6b2..72c1d19fa79f 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -2,7 +2,6 @@ */ #include #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e96c688cba9f..a16fc157a67d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index f76ca9e2eebf..77c37889232b 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -23,7 +23,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 255a47dfb84f..d3282ec62c5b 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 55d45b0032cf..e3894b68c4ee 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 585bd1fe0765..31062a981e36 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 2d709e064679..b3939a0bada0 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 784098d4bf04..03d31860851b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 210a84d8b971..bd495c12d29f 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index c4c5bd67f795..2bc6bdc9c1f2 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -12,7 +12,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index 3fe9fa04cd84..8063e33f1c85 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include "ovcamchip_priv.h" diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 9ea41c6699bb..1ea0939096ae 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 931b274bffca..d3ac70a0d9ca 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -64,7 +64,6 @@ #include #include #include -#include #include "pwc.h" #include "pwc-kiara.h" diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 3c0fc9027ad0..eb5e77dd0d18 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 25f84701a8e8..80108ddf4834 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index fc260ec8fdc2..7ed4eaf05e13 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 1cb8c709ca90..cc87f5855a21 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 1b6dfd801cc1..80d2644f765a 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 72444f039e3d..1a737b647366 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 60a90a2617ae..7780b2cce80d 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 18b4817b4aac..43501b5dc05b 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index f38366a470fa..0044079f5da2 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9985ded20950..9c317ed6b210 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 36d8a455e0ec..e0accf1b8713 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index e8597c10aa4c..d162bc67d445 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5f378265d8c5..baeae28f2836 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index f1ee60a4aa76..572f22423b98 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index cffb011590e3..a19cdcc17ef7 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index fdc3def437b1..4b2c4034f5b3 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -30,7 +30,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 3ae5a9cd2e28..544a4ae7d2ed 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -2,7 +2,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 5b1e346df206..c7d5f9ed22d7 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -45,7 +45,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 0cb006f2943d..2f9b2b9e3b09 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -68,7 +68,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index ede8543818bf..9eac65f34bff 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index a32dfbe0585a..f6f31e1773d1 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index a0c1647a2ba4..9a03dc82c6ca 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 8f31613b9903..77599f228b61 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -42,7 +42,6 @@ #include #include #include -#include #include "w9968cf.h" #include "w9968cf_decoder.h" diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 703b741e46df..35138c594be1 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include From aeb292d1342c649ac0b35ae9205b761fd14adb57 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Aug 2007 15:45:41 -0300 Subject: [PATCH 125/310] V4L/DVB (6081): ivtv: Fix static structure initialization Convert the initialization of ivtv_i2c_algo_template to C99-style. Otherwise a future change to struct i2c_algo_bit_data would break this code. Also declared that structure const - it's a template after all. Signed-off-by: Jean Delvare Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 5e12ebc2a9de..085dc3938da7 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -536,14 +536,13 @@ static struct i2c_adapter ivtv_i2c_adap_template = { #endif }; -static struct i2c_algo_bit_data ivtv_i2c_algo_template = { - NULL, /* ?? */ - ivtv_setsda_old, /* setsda function */ - ivtv_setscl_old, /* " */ - ivtv_getsda_old, /* " */ - ivtv_getscl_old, /* " */ - 10, /* udelay */ - 200 /* timeout */ +static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { + .setsda = ivtv_setsda_old, + .setscl = ivtv_setscl_old, + .getsda = ivtv_getsda_old, + .getscl = ivtv_getscl_old, + .udelay = 10, + .timeout = 200, }; static struct i2c_client ivtv_i2c_client_template = { From 16cf1d0c5d7b8970aca2ca426166833642ce0544 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 21 Aug 2007 08:19:16 -0300 Subject: [PATCH 126/310] V4L/DVB (6082): cx88: Improve risc instruction printing in sram channel dump When the risc instrunctions from the CMDS were printed, instruction arguments weren't taken into account. This changes output like: cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ INVALID sol eol 23 21 19 18 13 count=2048 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ INVALID sol eol 23 21 19 18 13 count=3072 ] cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ arg #1 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ arg #1 ] Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index cea3212d28b4..ce7f1f0ae054 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -434,10 +434,13 @@ void cx88_sram_channel_dump(struct cx88_core *core, printk("%s: cmds: %-12s: 0x%08x\n", core->name,name[i], cx_read(ch->cmds_start + 4*i)); - for (i = 0; i < 4; i++) { + for (n = 1, i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i+11)); printk("%s: risc%d: ", core->name, i); - cx88_risc_decode(risc); + if (--n) + printk("0x%08x [ arg #%d ]\n", risc, n); + else + n = cx88_risc_decode(risc); } for (i = 0; i < 16; i += n) { risc = cx_read(ch->ctrl_start + 4 * i); From 05b2723387cb4086535e935ee07cca19086308fc Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:34 -0300 Subject: [PATCH 127/310] V4L/DVB (6083): cx88-alsa: Rework buffer handling Rework the way the DMA buffer is handled and IRQs are generated. ALSA uses a ring-buffer of multiple periods. Each period is supposed to corrispond to one IRQ. The existing driver was generating one interrupt per ring-buffer, as opposed to per period. This meant that as soon as the IRQ was generated, the hardware was already starting to re-write the beginning of the buffer. Since the DMA happens on a per-line basis, there was only a narrow window to copy the data out before the buffer was overwritten. The cx88 core RISC program generator is modified so that it can set the IRQ and counter flags to count every X lines of DMA transfer. This way we can generate an interrupt every period instead of every full ring-buffer. Right now only period of one line are supported, but it should be possible to support longer periods. Note that a WRITE instruction generates an IRQ when it starts, not when the transfer is finished. Thus to generate an IRQ when line X is done, one must set the IRQ flag on the instruction that starts line X+1, not the one that ends line X. Change the line size so that there are four lines in the SRAM FIFO. If there are not four lines, the analog output from the cx88's internal DACs is full of clicks and pops. Try to handle FIFO sync errors. Sometimes the chip generates many of these errors before audio data starts. Up to 50 sync errors will be ignored and the counter reset. Have the IRQ handler save the RISC counter to the chip struct, and then have the pointer callback use this to calculate the pointer position. We could read the counter from the pointer callback, but sometimes the sync errors on start up cause the counter to go crazy. ALSA sees this and thinks there has been an overrun. The IRQ hander can avoid saving the counter position on sync errors. The chip "opened" flag wasn't necessary. ALSA won't try to open the same substream multiple times. Probably this code was cut&pasted from the bt87x driver, which has multiple sub-streams for one chip. Do error checking for the videobuf mapping functions. snd_card_cx88_runtime_free() is useless and can be deleted. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 168 ++++++++++++--------------- drivers/media/video/cx88/cx88-core.c | 22 ++-- drivers/media/video/cx88/cx88-mpeg.c | 2 +- drivers/media/video/cx88/cx88.h | 2 +- 4 files changed, 89 insertions(+), 105 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 8d19d33c8b32..33dd4cb5e877 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -3,6 +3,7 @@ * Support for audio capture * PCI function #1 of the cx2388x. * + * (c) 2007 Trent Piepho * (c) 2005,2006 Ricardo Cerqueira * (c) 2005 Mauro Carvalho Chehab * Based on a dummy cx88 module by Gerd Knorr @@ -47,7 +48,6 @@ #define dprintk_core(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) - /**************************************************************************** Data type declarations - Can be moded to a header file later ****************************************************************************/ @@ -58,6 +58,7 @@ struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; + u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -68,24 +69,20 @@ struct cx88_audio_dev { struct snd_card *card; spinlock_t reg_lock; + atomic_t count; unsigned int dma_size; unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf dma_risc; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; - long int read_count; - long int read_offset; - - struct cx88_buffer *buf; - - long opened; - struct snd_pcm_substream *substream; + struct cx88_buffer *buf; + struct snd_pcm_substream *substream; }; typedef struct cx88_audio_dev snd_cx88_card_t; @@ -146,16 +143,13 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_write(MO_AUDD_LNGTH, buf->bpl); /* reset counter */ - cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " - "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " + "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, chip->num_periods, buf->bpl * chip->num_periods); - dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", - chip->core->pci_irqmask, - chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); @@ -198,7 +192,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) return 0; } -#define MAX_IRQ_LOOP 10 +#define MAX_IRQ_LOOP 50 /* * BOARD Specific: IRQ dma bits @@ -223,14 +217,11 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) { struct cx88_core *core = chip->core; u32 status, mask; - u32 count; status = cx_read(MO_AUD_INTSTAT); mask = cx_read(MO_AUD_INTMSK); - if (0 == (status & mask)) { - spin_unlock(&chip->reg_lock); + if (0 == (status & mask)) return; - } cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq aud", @@ -238,27 +229,20 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); + printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } - + if (status & AUD_INT_DN_SYNC) { + dprintk(1, "Downstream sync error\n"); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + return; + } /* risc1 downstream */ if (status & AUD_INT_DN_RISCI1) { - spin_lock(&chip->reg_lock); - count = cx_read(MO_AUDD_GPCNT); - spin_unlock(&chip->reg_lock); - if (chip->read_count == 0) - chip->read_count += chip->dma_size; - } - - if (chip->read_count >= chip->period_size) { - dprintk(2, "Elapsing period\n"); + atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT)); snd_pcm_period_elapsed(chip->substream); } - - dprintk(3,"Leaving audio IRQ handler...\n"); - /* FIXME: Any other status should deserve a special handling? */ } @@ -277,23 +261,20 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; - dprintk( 3, "cx8801_irq\n" ); - dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); - dprintk( 3, " status: %d\n", status ); + dprintk(3, "cx8801_irq loop %d/%d, status %x\n", + loop, MAX_IRQ_LOOP, status); handled = 1; cx_write(MO_PCI_INTSTAT, status); if (status & core->pci_irqmask) cx88_core_irq(core, status); - if (status & PCI_INT_AUDINT) { - dprintk( 2, " ALSA IRQ handling\n" ); + if (status & PCI_INT_AUDINT) cx8801_aud_irq(chip); - } - }; + } if (MAX_IRQ_LOOP == loop) { - dprintk( 0, "clearing mask\n" ); - dprintk(1,"%s/0: irq loop -- clearing mask\n", + printk(KERN_ERR + "%s/1: IRQ loop detected, disabling interrupts\n", core->name); cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } @@ -315,7 +296,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) chip->dma_size = 0; - return 0; + return 0; } /**************************************************************************** @@ -325,6 +306,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) /* * Digital hardware definition */ +#define DEFAULT_FIFO_SIZE 4096 static struct snd_pcm_hardware snd_cx88_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -337,19 +319,15 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (2*2048), - .period_bytes_min = 2048, - .period_bytes_max = 2048, - .periods_min = 2, - .periods_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE/4, + .period_bytes_max = DEFAULT_FIFO_SIZE/4, + .periods_min = 1, + .periods_max = 1024, + .buffer_bytes_max = (1024*1024), }; -/* - * audio pcm capture runtime free - */ -static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime) -{ -} /* * audio pcm capture open callback */ @@ -359,26 +337,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if (test_and_set_bit(0, &chip->opened)) - return -EBUSY; - - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; chip->substream = substream; - chip->read_count = 0; - chip->read_offset = 0; - - runtime->private_free = snd_card_cx88_runtime_free; runtime->hw = snd_cx88_digital_hw; + if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { + unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + return 0; _error: dprintk(1,"Error opening PCM!\n"); - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); return err; } @@ -387,11 +363,6 @@ _error: */ static int snd_cx88_close(struct snd_pcm_substream *substream) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); - return 0; } @@ -403,54 +374,61 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct cx88_buffer *buf; + int ret; if (substream->runtime->dma_area) { dsp_buffer_free(chip); substream->runtime->dma_area = NULL; } - chip->period_size = params_period_bytes(hw_params); chip->num_periods = params_periods(hw_params); chip->dma_size = chip->period_size * params_periods(hw_params); BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods-1)); - dprintk(1,"Setting buffer\n"); - - buf = kzalloc(sizeof(*buf),GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (NULL == buf) return -ENOMEM; buf->vb.memory = V4L2_MEMORY_MMAP; + buf->vb.field = V4L2_FIELD_NONE; buf->vb.width = chip->period_size; + buf->bpl = chip->period_size; buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - buf->vb.field = V4L2_FIELD_NONE; videobuf_dma_init(&buf->vb.dma); - videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE, + ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; - videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + if (ret < 0) + goto error; + ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + buf->vb.width, buf->vb.height, 1); + if (ret < 0) + goto error; - cx88_risc_databuffer(chip->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); - - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->vb.state = STATE_PREPARED; - buf->bpl = chip->period_size; chip->buf = buf; chip->dma_risc = buf->vb.dma; - dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages); substream->runtime->dma_area = chip->dma_risc.vmalloc; return 0; + +error: + kfree(buf); + return ret; } /* @@ -477,7 +455,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream) return 0; } - /* * trigger callback */ @@ -486,6 +463,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); int err; + /* Local interrupts are already disabled by ALSA */ spin_lock(&chip->reg_lock); switch (cmd) { @@ -512,17 +490,14 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; - if (chip->read_count) { - chip->read_count -= snd_pcm_lib_period_bytes(substream); - chip->read_offset += snd_pcm_lib_period_bytes(substream); - if (chip->read_offset == chip->dma_size) - chip->read_offset = 0; - } - - dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count); - return bytes_to_frames(runtime, chip->read_offset); + count = atomic_read(&chip->count); +// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__, +// count, new, count & (runtime->periods-1), +// runtime->period_size * (count & (runtime->periods-1))); + return runtime->period_size * (count & (runtime->periods-1)); } /* @@ -592,10 +567,13 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, int v; u32 old_control; + /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); + old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); v = 0x3f - (value->value.integer.value[0] & 0x3f); cx_andor(AUD_VOL_CTL, 0x3f, v); + spin_unlock_irq(&chip->reg_lock); return v != old_control; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ce7f1f0ae054..41f7f374c183 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -68,13 +68,15 @@ static DEFINE_MUTEX(devlist); #define NO_SYNC_LINE (-1U) +/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be + generated _after_ lpi lines are transferred. */ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, unsigned int lpi) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line,todo,sol; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -87,15 +89,19 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg++; } + if (lpi && line>0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); offset+=bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++)=cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); todo -= (sg_dma_len(sg)-offset); @@ -146,10 +152,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx88_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines, 0); if (UNSET != bottom_offset) rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines, 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -159,7 +165,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + unsigned int lines, unsigned int lpi) { u32 instructions; u32 *rp; @@ -176,7 +182,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi); /* save pointer to jmp instruction address */ risc->jmp = rp; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6ece35b5fc83..4e6a84f15d17 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -253,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 80e49f986fbb..e436a37b4404 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -519,7 +519,7 @@ cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, extern int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines); + unsigned int lines, unsigned int lpi); extern int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); From ffb7394d51cf6f60a3753a5cc40613fc9d5c5c96 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:35 -0300 Subject: [PATCH 128/310] V4L/DVB (6084): cx88-alsa: Eliminate snd_cx88_cards The driver kepts a static global array of snd_card pointers for each card probed, which was never used. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 33dd4cb5e877..ac317fb856e4 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -95,7 +95,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; -static struct snd_card *snd_cx88_cards[SNDRV_CARDS]; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); @@ -759,8 +758,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, snd_card_free(card); return (err); } - snd_cx88_cards[devno] = card; - pci_set_drvdata(pci,card); devno++; From f6210c9160dff82ceaaf5e59cf5f8fcd6bdefa38 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:36 -0300 Subject: [PATCH 129/310] V4L/DVB (6085): cx88-alsa: Fix mmap support The driver has long claimed to support mmap, but it didn't work at all. Some of the dma buffer parameters weren't set, and since video_buf uses vmalloc to allocate the buffer, a page callback is needed too. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ac317fb856e4..85d632224f3a 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -423,6 +424,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, chip->dma_risc = buf->vb.dma; substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; return 0; error: @@ -499,6 +502,16 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) return runtime->period_size * (count & (runtime->periods-1)); } +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx88_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + /* * operators */ @@ -511,6 +524,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = { .prepare = snd_cx88_prepare, .trigger = snd_cx88_card_trigger, .pointer = snd_cx88_pointer, + .page = snd_cx88_page, }; /* From ad8ff0f10b489562012e433acdac92498fe8bdc9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:01:58 -0300 Subject: [PATCH 130/310] V4L/DVB (6086): ivtv: fix output mode processing: UDMA_YUV wasn't cleared - Always clear when stopping the decoder - Clear if the filehandle that is being close was used for UDMA_YUV output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 + drivers/media/video/ivtv/ivtv-fileops.c | 7 ++----- drivers/media/video/ivtv/ivtv-ioctl.c | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 03d31860851b..3ed4703956d3 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -517,6 +517,7 @@ struct ivtv_stream { struct ivtv_open_id { u32 open_id; int type; + int yuv_frames; enum v4l2_priority prio; struct ivtv *itv; }; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 1f3c8d0310f5..62ee41c5220b 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -757,6 +757,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) IVTV_DEBUG_INFO("close stopping decode\n"); ivtv_stop_v4l2_decode_stream(s, flags, pts); + itv->output_mode = OUT_NONE; } clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); @@ -764,11 +765,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) /* Restore registers we've changed & clean up any mess we've made */ ivtv_yuv_close(itv); } - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) itv->output_mode = OUT_NONE; itv->speed = 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index ed5707660e0e..2bb1e324785b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1346,6 +1346,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_release_stream(s); return -EBUSY; } + /* Mark that this file handle started the UDMA_YUV mode */ + id->yuv_frames = 1; if (args->y_source == NULL) return 0; return ivtv_yuv_prep_frame(itv, args); From ea115d54bc963eb2eb0dc223795f3bd6c689ff99 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:26:40 -0300 Subject: [PATCH 131/310] V4L/DVB (6087): ivtv: prevent changing VBI format while capture is in progress Changing the VBI format requires a CX2341X_ENC_INITIALIZE_INPUT firmware call. This can only be done if no capture is in progress. So return -EBUSY if the encoder is busy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2bb1e324785b..0dde82f67e26 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -584,9 +584,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, /* set raw VBI format */ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && - itv->vbi.sliced_in->service_set && - atomic_read(&itv->capturing) > 0) { + if (set_fmt && atomic_read(&itv->capturing) > 0) { return -EBUSY; } if (set_fmt) { @@ -624,7 +622,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, return 0; if (set == 0) return -EINVAL; - if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { + if (atomic_read(&itv->capturing) > 0) { return -EBUSY; } itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); From 01f1e44fe8455b6c6c557a62119b8622fb99f5f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 21 Aug 2007 18:32:42 -0300 Subject: [PATCH 132/310] V4L/DVB (6088): cx2341x: some controls can't be changed while the device is busy The driver should now pass the 'busy' state of the device to the cx2341x module whenever controls are set or tried. -EBUSY will be returned if the device is busy and the user attempts to modify certain 'dangerous' controls. It concerns controls that change the audio or video compression mode and bitrates. The cx88-blackbird and pvrusb2 drivers currently always pass '0' (not busy) to the cx2341x, effectively keeping the old behavior for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 18 +++++++++++++++--- drivers/media/video/cx88/cx88-blackbird.c | 6 +++--- drivers/media/video/ivtv/ivtv-controls.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 +++--- drivers/media/video/v4l2-common.c | 1 + include/media/cx2341x.h | 2 +- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 904bba0dbc4d..62304255dcae 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -190,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, /* Map the control ID to the correct field in the cx2341x_mpeg_params struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_control *ctrl) { switch (ctrl->id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_MODE: @@ -245,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_gop_closure = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; /* MPEG-1 only allows CBR */ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -252,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_bitrate_mode = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; params->video_bitrate = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; params->video_bitrate_peak = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: @@ -267,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_mute_yuv = ctrl->value; break; case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || @@ -631,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) (params->audio_crc << 14); } -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd) { int err = 0; @@ -663,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); if (err) break; - err = cx2341x_set_ctrl(params, ctrl); + err = cx2341x_set_ctrl(params, busy, ctrl); if (err) break; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 206af419aea7..47007380a98a 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -876,7 +876,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS); + return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); } static int vidioc_s_ext_ctrls (struct file *file, void *priv, @@ -889,7 +889,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); dev->params = p; @@ -907,7 +907,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); return err; } diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 7a876c3e5b19..0005ea46f208 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -232,7 +232,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, arg, cmd); + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); if (err) return err; @@ -282,7 +282,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); return -EINVAL; } @@ -292,7 +292,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); return -EINVAL; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1311891e7ee3..2d5be5cfbccf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) cs.controls = &c1; cs.count = 1; c1.id = cptr->info->v4l_id; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_G_EXT_CTRLS); if (ret) return ret; *vp = c1.value; @@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_S_EXT_CTRLS); if (ret) return ret; cptr->hdw->enc_stale = !0; @@ -2478,7 +2478,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cs.count = 1; c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; c1.value = hdw->srate_val; - cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); + cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); } /* Scan i2c core at this point - before we clear all the dirty diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index d2915d3530ea..0689a041d777 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -716,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: case V4L2_CID_MPEG_AUDIO_MUTE: + case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index 38c12fed7535..af8071d7620d 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -91,7 +91,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl); const char **cx2341x_ctrl_get_menu(u32 id); -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix); From d2a35fb172845fe75c40a3ee9c95656c7c115e48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:43:34 -0300 Subject: [PATCH 133/310] V4L/DVB (6089): ivtv: log in status if framebuffer uses YUV instead of RGB Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 0dde82f67e26..bb59634419cc 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1270,7 +1270,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Global and Local" }; static const char * const pixel_format[] = { - "Indexed", + "RGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1278,6 +1278,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", + "YUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", }; ivtv_get_output(itv, itv->active_output, &vidout); @@ -1290,10 +1298,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", data[0] & 1 ? "On" : "Off", alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0x7]); + pixel_format[(data[0] >> 3) & 0xf]); } IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); From 459a52fab2c42cd5fadfd51fdcfc6dea8107fabf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:58:47 -0300 Subject: [PATCH 134/310] V4L/DVB (6090): ivtv-fb: correct transparency bit reporting Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 008076543aca..7618cd47a35d 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -608,9 +608,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { - var->transp.offset = 0; - var->transp.length = 0; - /* To find out the true mode, check green length */ switch (var->green.length) { case 4: @@ -620,6 +617,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 4; var->blue.offset = 0; var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; break; case 5: var->red.offset = 10; @@ -628,6 +627,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; break; default: var->red.offset = 11; @@ -636,6 +637,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; break; } } From 612570f2c4794bbf4e5bfa8648b61fbfc9cd8501 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 05:42:59 -0300 Subject: [PATCH 135/310] V4L/DVB (6091): ivtv: header cleanup - add guards - remove unused header includes - move card-specific stuff from ivtv-driver.h to ivtv-cards.h - move YUV-specific stuff from ivtv-driver.h to ivtv-yuv.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-audio.c | 3 - drivers/media/video/ivtv/ivtv-audio.h | 5 ++ drivers/media/video/ivtv/ivtv-cards.h | 64 ++++++++++++++++++++ drivers/media/video/ivtv/ivtv-controls.h | 5 ++ drivers/media/video/ivtv/ivtv-driver.c | 7 --- drivers/media/video/ivtv/ivtv-driver.h | 74 +----------------------- drivers/media/video/ivtv/ivtv-fileops.c | 1 - drivers/media/video/ivtv/ivtv-fileops.h | 5 ++ drivers/media/video/ivtv/ivtv-firmware.h | 5 ++ drivers/media/video/ivtv/ivtv-gpio.h | 5 ++ drivers/media/video/ivtv/ivtv-i2c.h | 5 ++ drivers/media/video/ivtv/ivtv-ioctl.h | 5 ++ drivers/media/video/ivtv/ivtv-irq.c | 3 - drivers/media/video/ivtv/ivtv-irq.h | 5 ++ drivers/media/video/ivtv/ivtv-mailbox.h | 5 ++ drivers/media/video/ivtv/ivtv-queue.c | 2 - drivers/media/video/ivtv/ivtv-queue.h | 5 ++ drivers/media/video/ivtv/ivtv-streams.c | 8 +-- drivers/media/video/ivtv/ivtv-streams.h | 5 ++ drivers/media/video/ivtv/ivtv-udma.c | 1 - drivers/media/video/ivtv/ivtv-udma.h | 5 ++ drivers/media/video/ivtv/ivtv-vbi.h | 5 ++ drivers/media/video/ivtv/ivtv-version.h | 5 ++ drivers/media/video/ivtv/ivtv-video.h | 5 ++ drivers/media/video/ivtv/ivtv-yuv.c | 9 ++- drivers/media/video/ivtv/ivtv-yuv.h | 18 ++++++ 26 files changed, 167 insertions(+), 98 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c index d702b8b539a1..6cb65d69c986 100644 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ b/drivers/media/video/ivtv/ivtv-audio.c @@ -19,13 +19,10 @@ */ #include "ivtv-driver.h" -#include "ivtv-mailbox.h" #include "ivtv-i2c.h" -#include "ivtv-gpio.h" #include "ivtv-cards.h" #include "ivtv-audio.h" #include -#include /* Selects the audio input and output according to the current settings. */ diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h index 9c42846d8124..ebb90cc8f861 100644 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ b/drivers/media/video/ivtv/ivtv-audio.h @@ -18,6 +18,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_AUDIO_H +#define IVTV_AUDIO_H + int ivtv_audio_set_io(struct ivtv *itv); void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 3191920f4c6b..ff46e5ae8653 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -18,6 +18,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CARDS_H +#define IVTV_CARDS_H + +/* Supported cards */ +#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ +#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ +#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two + PVR150s on one PCI board) */ +#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ +#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ +#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 + cx23415 based, but does not have tv-out */ +#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ +#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ +#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ +#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ +#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ +#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ +#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ +#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ +#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ +#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ +#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 + +/* Variants of existing cards but with the same PCI IDs. The driver + detects these based on other device information. + These cards must always come last. + New cards must be inserted above, and the indices of the cards below + must be adjusted accordingly. */ + +/* PVR-350 V1 (uses saa7114) */ +#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) +/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) +#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_ICOMP 0x4444 +#define PCI_DEVICE_ID_IVTV15 0x0803 +#define PCI_DEVICE_ID_IVTV16 0x0016 + +/* subsystem vendor ID */ +#define IVTV_PCI_ID_HAUPPAUGE 0x0070 +#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 +#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 +#define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_AVERMEDIA 0x1461 +#define IVTV_PCI_ID_YUAN1 0x12ab +#define IVTV_PCI_ID_YUAN2 0xff01 +#define IVTV_PCI_ID_YUAN3 0xffab +#define IVTV_PCI_ID_YUAN4 0xfbab +#define IVTV_PCI_ID_DIAMONDMM 0xff92 +#define IVTV_PCI_ID_IODATA 0x10fc +#define IVTV_PCI_ID_MELCO 0x1154 +#define IVTV_PCI_ID_GOTVIEW1 0xffac +#define IVTV_PCI_ID_GOTVIEW2 0xffad + /* hardware flags */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) @@ -206,3 +268,5 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); const struct ivtv_card *ivtv_get_card(u16 index); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h index 5a11149725ad..bb8a6a5ed2bc 100644 --- a/drivers/media/video/ivtv/ivtv-controls.h +++ b/drivers/media/video/ivtv/ivtv-controls.h @@ -18,4 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CONTROLS_H +#define IVTV_CONTROLS_H + int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 93ddea49f0ed..2ed9894672f4 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -87,13 +87,6 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 -}; - /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 3ed4703956d3..f7849f852e9d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -74,61 +74,10 @@ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ -#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ - -/* Offset to filter table in firmware */ -#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 -#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 - -extern const u32 yuv_offset[4]; - /* Maximum ivtv driver instances. Some people have a huge number of capture cards, so set this to a high value. */ #define IVTV_MAX_CARDS 32 -/* Supported cards */ -#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ -#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ -#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two - PVR150s on one PCI board) */ -#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ -#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ -#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 - cx23415 based, but does not have tv-out */ -#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ -#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ -#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ -#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ -#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ -#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ -#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ -#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ -#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ -#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ -#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ -#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ -#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 - -/* Variants of existing cards but with the same PCI IDs. The driver - detects these based on other device information. - These cards must always come last. - New cards must be inserted above, and the indices of the cards below - must be adjusted accordingly. */ - -/* PVR-350 V1 (uses saa7114) */ -#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) -/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) -#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) - #define IVTV_ENC_STREAM_TYPE_MPG 0 #define IVTV_ENC_STREAM_TYPE_YUV 1 #define IVTV_ENC_STREAM_TYPE_VBI 2 @@ -150,27 +99,6 @@ extern const u32 yuv_offset[4]; #define IVTV_ENC_MEM_START 0x00000000 #define IVTV_DEC_MEM_START 0x01000000 -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_ICOMP 0x4444 -#define PCI_DEVICE_ID_IVTV15 0x0803 -#define PCI_DEVICE_ID_IVTV16 0x0016 - -/* subsystem vendor ID */ -#define IVTV_PCI_ID_HAUPPAUGE 0x0070 -#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 -#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 -#define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_AVERMEDIA 0x1461 -#define IVTV_PCI_ID_YUAN1 0x12ab -#define IVTV_PCI_ID_YUAN2 0xff01 -#define IVTV_PCI_ID_YUAN3 0xffab -#define IVTV_PCI_ID_YUAN4 0xfbab -#define IVTV_PCI_ID_DIAMONDMM 0xff92 -#define IVTV_PCI_ID_IODATA 0x10fc -#define IVTV_PCI_ID_MELCO 0x1154 -#define IVTV_PCI_ID_GOTVIEW1 0xffac -#define IVTV_PCI_ID_GOTVIEW2 0xffad - /* Decoder Buffer hardware size on Chip */ #define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ #define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ @@ -890,4 +818,4 @@ int ivtv_init_on_first_open(struct ivtv *itv); #define write_dec_sync(val, addr) \ do { write_dec(val, addr); read_dec(addr); } while (0) -#endif /* IVTV_DRIVER_H */ +#endif diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 62ee41c5220b..6449f5831e66 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -30,7 +30,6 @@ #include "ivtv-audio.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" -#include "ivtv-controls.h" #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h index 74a1745fabbc..2c8d5186c9c3 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.h +++ b/drivers/media/video/ivtv/ivtv-fileops.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FILEOPS_H +#define IVTV_FILEOPS_H + /* Testing/Debugging */ int ivtv_v4l2_open(struct inode *inode, struct file *filp); ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, @@ -42,3 +45,5 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type); /* Release a previously claimed stream. */ void ivtv_release_stream(struct ivtv_stream *s); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h index 8b2ffe658905..041ba94e65bc 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.h +++ b/drivers/media/video/ivtv/ivtv-firmware.h @@ -19,7 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FIRMWARE_H +#define IVTV_FIRMWARE_H + int ivtv_firmware_init(struct ivtv *itv); void ivtv_firmware_versions(struct ivtv *itv); void ivtv_halt_firmware(struct ivtv *itv); void ivtv_init_mpeg_decoder(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index b31c679bbd8e..964a265d91a9 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_GPIO_H +#define IVTV_GPIO_H + /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 5d210adb5c52..677c3292855e 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_I2C_H +#define IVTV_I2C_H + int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); @@ -34,3 +37,5 @@ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); /* init + register i2c algo-bit adapter */ int __devinit init_ivtv_i2c(struct ivtv *itv); void __devexit exit_ivtv_i2c(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index cbccf7a9f65c..a03351b6853d 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IOCTL_H +#define IVTV_IOCTL_H + u16 service2vbi(int type); void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); @@ -26,3 +29,5 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index d68853fd60a3..b6a94a1ad19b 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -19,12 +19,9 @@ */ #include "ivtv-driver.h" -#include "ivtv-firmware.h" -#include "ivtv-fileops.h" #include "ivtv-queue.h" #include "ivtv-udma.h" #include "ivtv-irq.h" -#include "ivtv-ioctl.h" #include "ivtv-mailbox.h" #include "ivtv-vbi.h" #include "ivtv-yuv.h" diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index a43348a30309..e180bd348989 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -19,8 +19,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IRQ_H +#define IVTV_IRQ_H + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); void ivtv_unfinished_dma(unsigned long arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 79b8aec14370..90c871b8e23b 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_MAILBOX_H +#define IVTV_MAILBOX_H + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index d9a1478ca1f7..437f134796e3 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -20,9 +20,7 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-queue.h" -#include "ivtv-mailbox.h" int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) { diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 14a9f7fe50aa..7cfc0c9ab050 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -19,6 +19,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_QUEUE_H +#define IVTV_QUEUE_H + #define IVTV_DMA_UNMAPPED ((u32) -1) #define SLICED_VBI_PIO 1 @@ -89,3 +92,5 @@ static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index ebf925c549fd..fae151a31e85 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -35,16 +35,12 @@ #include "ivtv-driver.h" #include "ivtv-fileops.h" -#include "ivtv-i2c.h" #include "ivtv-queue.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" #include "ivtv-ioctl.h" -#include "ivtv-irq.h" -#include "ivtv-streams.h" +#include "ivtv-yuv.h" #include "ivtv-cards.h" +#include "ivtv-streams.h" static struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h index 8597b75384a7..8f5f5b1c7c89 100644 --- a/drivers/media/video/ivtv/ivtv-streams.h +++ b/drivers/media/video/ivtv/ivtv-streams.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_STREAMS_H +#define IVTV_STREAMS_H + int ivtv_streams_setup(struct ivtv *itv); void ivtv_streams_cleanup(struct ivtv *itv); @@ -29,3 +32,5 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); void ivtv_stop_all_captures(struct ivtv *itv); int ivtv_passthrough_mode(struct ivtv *itv, int enable); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 7e503adacea0..c4626d1cdf41 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -21,7 +21,6 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-udma.h" void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h index e131bccedec0..df727e23be0a 100644 --- a/drivers/media/video/ivtv/ivtv-udma.h +++ b/drivers/media/video/ivtv/ivtv-udma.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_UDMA_H +#define IVTV_UDMA_H + /* User DMA functions */ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); @@ -41,3 +44,5 @@ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index ec211b49702c..d5740493a690 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VBI_H +#define IVTV_VBI_H + ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); @@ -24,3 +27,5 @@ int ivtv_used_line(struct ivtv *itv, int line, int field); void ivtv_disable_vbi(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 122d56105969..d050de2a7229 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VERSION_H +#define IVTV_VERSION_H + #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 1 @@ -24,3 +27,5 @@ #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h index c8ade5d3c413..498e9b61c227 100644 --- a/drivers/media/video/ivtv/ivtv-video.h +++ b/drivers/media/video/ivtv/ivtv-video.h @@ -17,8 +17,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VIDEO_H +#define IVTV_VIDEO_H + void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, u8 vps4, u8 vps5); void ivtv_video_set_io(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 1922c1da20d3..bb2cbb206c14 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -19,11 +19,16 @@ */ #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" #include "ivtv-yuv.h" +const u32 yuv_offset[4] = { + IVTV_YUV_BUFFER_OFFSET, + IVTV_YUV_BUFFER_OFFSET_1, + IVTV_YUV_BUFFER_OFFSET_2, + IVTV_YUV_BUFFER_OFFSET_3 +}; + static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, struct ivtv_dma_frame *args) { diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 88972d3f77c4..0824048ce3a2 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -18,7 +18,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_YUV_H +#define IVTV_YUV_H + +/* Buffers on hardware offsets */ +#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ +#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ + +/* Offset to filter table in firmware */ +#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 +#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 + +extern const u32 yuv_offset[4]; + int ivtv_yuv_filter_check(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); void ivtv_yuv_work_handler (struct ivtv *itv); + +#endif From 33c0fcad2160bc211272295e862c6f708118d006 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 06:32:46 -0300 Subject: [PATCH 136/310] V4L/DVB (6092): ivtv: more cleanups, merged ivtv-audio.c and ivtv-video.c into ivtv-routing.c Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Makefile | 4 +- drivers/media/video/ivtv/ivtv-audio.c | 71 ----------- drivers/media/video/ivtv/ivtv-controls.c | 10 +- drivers/media/video/ivtv/ivtv-driver.c | 14 ++- drivers/media/video/ivtv/ivtv-driver.h | 113 +++--------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-fileops.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 5 +- drivers/media/video/ivtv/ivtv-irq.h | 22 ++++ drivers/media/video/ivtv/ivtv-mailbox.h | 3 + .../ivtv/{ivtv-video.c => ivtv-routing.c} | 92 +++++--------- .../ivtv/{ivtv-audio.h => ivtv-routing.h} | 11 +- drivers/media/video/ivtv/ivtv-streams.c | 16 ++- drivers/media/video/ivtv/ivtv-vbi.c | 64 +++++++++- drivers/media/video/ivtv/ivtv-video.h | 29 ----- drivers/media/video/ivtv/ivtv-yuv.c | 4 +- drivers/media/video/ivtv/ivtv-yuv.h | 3 + 17 files changed, 185 insertions(+), 280 deletions(-) delete mode 100644 drivers/media/video/ivtv/ivtv-audio.c rename drivers/media/video/ivtv/{ivtv-video.c => ivtv-routing.c} (59%) rename drivers/media/video/ivtv/{ivtv-audio.h => ivtv-routing.h} (77%) delete mode 100644 drivers/media/video/ivtv/ivtv-video.h diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 90e2d1270561..6998781e2b11 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -1,8 +1,8 @@ -ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ +ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ - ivtv-vbi.o ivtv-video.o ivtv-yuv.o + ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c deleted file mode 100644 index 6cb65d69c986..000000000000 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ivtv-driver.h" -#include "ivtv-i2c.h" -#include "ivtv-cards.h" -#include "ivtv-audio.h" -#include - -/* Selects the audio input and output according to the current - settings. */ -int ivtv_audio_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - u32 audio_input; - int mux_input; - - /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } - - /* handle muxer chips */ - route.input = mux_input; - route.output = 0; - ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } - return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); -} - -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) -{ - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); -} - -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) -{ - static u32 freqs[3] = { 44100, 48000, 32000 }; - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (freq > 2) - return; - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); -} - diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 0005ea46f208..8c02fa661591 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -21,7 +21,7 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-ioctl.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-i2c.h" #include "ivtv-mailbox.h" #include "ivtv-controls.h" @@ -231,8 +231,10 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + static u32 freqs[3] = { 44100, 48000, 32000 }; struct cx2341x_mpeg_params p = itv->params; int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); + unsigned idx; if (err) return err; @@ -254,7 +256,11 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } itv->params = p; itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); + idx = p.audio_properties & 0x03; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < sizeof(freqs)) + ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); return err; } return -EINVAL; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2ed9894672f4..6a74e509c87d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -52,7 +52,7 @@ #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-gpio.h" #include "ivtv-yuv.h" @@ -106,6 +106,18 @@ static char secam[] = "--"; static char ntsc[] = "-"; /* Buffers */ + +/* DMA Buffers, Default size in MB allocated */ +#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 +#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 +#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 +#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 +#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 + static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f7849f852e9d..b9dfdab66362 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -65,12 +65,11 @@ #include +/* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 -#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_DECODER_OFFSET 0x01000000 -#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 @@ -89,51 +88,8 @@ #define IVTV_DEC_STREAM_TYPE_YUV 8 #define IVTV_MAX_STREAMS 9 -#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ -#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ -#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ -#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ - -#define IVTV_ENC_MEM_START 0x00000000 -#define IVTV_DEC_MEM_START 0x01000000 - -/* Decoder Buffer hardware size on Chip */ -#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ -#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - #define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ -/* DMA Buffers, Default size in MB allocated */ -#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 -#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 -#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -/* Exception: size in kB for this stream (MB is overkill) */ -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 -#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 -#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -/* Exception: size in kB for this stream (MB is way overkill) */ -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 - -/* ======================================================================== */ -/* ========================== END USER SETTABLE DMA VARIABLES ============= */ -/* ======================================================================== */ - -/* Decoder Status Register */ -#define IVTV_DMA_ERR_LIST 0x00000010 -#define IVTV_DMA_ERR_WRITE 0x00000008 -#define IVTV_DMA_ERR_READ 0x00000004 -#define IVTV_DMA_SUCCESS_WRITE 0x00000002 -#define IVTV_DMA_SUCCESS_READ 0x00000001 -#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) -#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) -#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) - /* DMA Registers */ #define IVTV_REG_DMAXFER (0x0000) #define IVTV_REG_DMASTATUS (0x0004) @@ -156,32 +112,11 @@ #define IVTV_REG_VPU (0x9058) #define IVTV_REG_APU (0xA064) -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) - -/* IRQ Masks */ -#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ - IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) - -#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) -#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) - /* i2c stuff */ #define I2C_CLIENTS_MAX 16 /* debugging */ +extern int ivtv_debug; #define IVTV_DBGFLG_WARN (1 << 0) #define IVTV_DBGFLG_INFO (1 << 1) @@ -235,11 +170,6 @@ #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ -#define MPEG_FRAME_TYPE_IFRAME 1 -#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 -#define MPEG_FRAME_TYPE_ALL 7 - /* output modes (cx23415 only) */ #define OUT_NONE 0 #define OUT_MPG 1 @@ -249,9 +179,6 @@ #define IVTV_MAX_PGM_INDEX (400) -extern int ivtv_debug; - - struct ivtv_options { int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ @@ -260,11 +187,6 @@ struct ivtv_options { int newi2c; /* New I2C algorithm */ }; -#define IVTV_MBOX_DMA_START 6 -#define IVTV_MBOX_DMA_END 8 -#define IVTV_MBOX_DMA 9 -#define IVTV_MBOX_FIELD_DISPLAYED 8 - /* ivtv-specific mailbox template */ struct ivtv_mailbox { u32 flags; @@ -450,31 +372,28 @@ struct ivtv_open_id { struct ivtv *itv; }; -#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 -#define IVTV_YUV_UPDATE_VERTICAL 0x02 - struct yuv_frame_info { u32 update; - int src_x; - int src_y; - unsigned int src_w; - unsigned int src_h; - int dst_x; - int dst_y; - unsigned int dst_w; - unsigned int dst_h; - int pan_x; - int pan_y; + s32 src_x; + s32 src_y; + u32 src_w; + u32 src_h; + s32 dst_x; + s32 dst_y; + u32 dst_w; + u32 dst_h; + s32 pan_x; + s32 pan_y; u32 vis_w; u32 vis_h; u32 interlaced_y; u32 interlaced_uv; - int tru_x; + s32 tru_x; u32 tru_w; u32 tru_h; u32 offset_y; - int lace_mode; + s32 lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 7618cd47a35d..2c521d1bb057 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -382,7 +382,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 6449f5831e66..170bef61aa62 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -27,7 +27,7 @@ #include "ivtv-irq.h" #include "ivtv-vbi.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index bb59634419cc..f4f56a6e1f81 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -25,8 +25,7 @@ #include "ivtv-queue.h" #include "ivtv-fileops.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" @@ -675,7 +674,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *route = arg; - ivtv_audio_set_route(itv, route); + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index e180bd348989..f879a5822e71 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -22,6 +22,28 @@ #ifndef IVTV_IRQ_H #define IVTV_IRQ_H +#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) +#define IVTV_IRQ_ENC_EOS (0x1 << 30) +#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) +#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) +#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) +#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) +#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) +#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) +#define IVTV_IRQ_DMA_ERR (0x1 << 18) +#define IVTV_IRQ_DMA_WRITE (0x1 << 17) +#define IVTV_IRQ_DMA_READ (0x1 << 16) +#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) + +/* IRQ Masks */ +#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ + IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) + +#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) +#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 90c871b8e23b..71a54eef8fc7 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -21,6 +21,9 @@ #ifndef IVTV_MAILBOX_H #define IVTV_MAILBOX_H +#define IVTV_MBOX_DMA_END 8 +#define IVTV_MBOX_DMA 9 + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-routing.c similarity index 59% rename from drivers/media/video/ivtv/ivtv-video.c rename to drivers/media/video/ivtv/ivtv-routing.c index 5858b197d510..398bd33033ed 100644 --- a/drivers/media/video/ivtv/ivtv-video.c +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -1,6 +1,7 @@ /* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,73 +19,46 @@ */ #include "ivtv-driver.h" -#include "ivtv-video.h" #include "ivtv-i2c.h" -#include "ivtv-gpio.h" #include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "ivtv-routing.h" + +#include #include #include -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) +/* Selects the audio input and output according to the current + settings. */ +void ivtv_audio_set_io(struct ivtv *itv) { - struct v4l2_sliced_vbi_data data; + struct v4l2_routing route; + u32 audio_input; + int mux_input; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_VPS; - data.field = 0; - data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); - data.field = 1; - data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - /* When using a 50 Hz system, always turn on the - wide screen signal with 4x3 ratio as the default. - Turning this signal on and off can confuse certain - TVs. As far as I can tell there is no reason not to - transmit this signal. */ - if ((itv->std & V4L2_STD_625_50) && !enabled) { - enabled = 1; - mode = 0x08; /* 4x3 full format */ + /* Determine which input to use */ + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + audio_input = itv->card->radio_input.audio_input; + mux_input = itv->card->radio_input.muxer_input; + } else { + audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; + mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; } - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - data.line = enabled ? 23 : 0; - data.data[0] = mode & 0xff; - data.data[1] = (mode >> 8) & 0xff; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + } + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } +/* Selects the video input and output according to the current + settings. */ void ivtv_video_set_io(struct ivtv *itv) { struct v4l2_routing route; diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-routing.h similarity index 77% rename from drivers/media/video/ivtv/ivtv-audio.h rename to drivers/media/video/ivtv/ivtv-routing.h index ebb90cc8f861..c72a9731ca01 100644 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ b/drivers/media/video/ivtv/ivtv-routing.h @@ -1,5 +1,5 @@ /* - Audio-related ivtv functions. + Audio/video-routing-related ivtv functions. Copyright (C) 2003-2004 Kevin Thayer Copyright (C) 2005-2007 Hans Verkuil @@ -18,11 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef IVTV_AUDIO_H -#define IVTV_AUDIO_H +#ifndef IVTV_ROUTING_H +#define IVTV_ROUTING_H -int ivtv_audio_set_io(struct ivtv *itv); -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); +void ivtv_audio_set_io(struct ivtv *itv); +void ivtv_video_set_io(struct ivtv *itv); #endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fae151a31e85..3939a804f043 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -38,6 +38,7 @@ #include "ivtv-queue.h" #include "ivtv-mailbox.h" #include "ivtv-ioctl.h" +#include "ivtv-irq.h" #include "ivtv-yuv.h" #include "ivtv-cards.h" #include "ivtv-streams.h" @@ -62,6 +63,13 @@ static struct file_operations ivtv_v4l2_dec_fops = { .poll = ivtv_v4l2_dec_poll, }; +#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ +#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ +#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ +#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ + static struct { const char *name; int vfl_type; @@ -658,10 +666,10 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a58c833c2b04..5d8a40f3d2b6 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -18,10 +18,70 @@ */ #include "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" +#include "ivtv-i2c.h" #include "ivtv-ioctl.h" #include "ivtv-queue.h" +#include "ivtv-vbi.h" + +static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, + u8 vps4, u8 vps5) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_VPS; + data.field = 0; + data.line = enabled ? 16 : 0; + data.data[4] = vps1; + data.data[10] = vps2; + data.data[11] = vps3; + data.data[12] = vps4; + data.data[13] = vps5; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_CAPTION_525; + data.field = 0; + data.line = (mode & 1) ? 21 : 0; + data.data[0] = cc1; + data.data[1] = cc2; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); + data.field = 1; + data.line = (mode & 2) ? 21 : 0; + data.data[0] = cc3; + data.data[1] = cc4; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + /* When using a 50 Hz system, always turn on the + wide screen signal with 4x3 ratio as the default. + Turning this signal on and off can confuse certain + TVs. As far as I can tell there is no reason not to + transmit this signal. */ + if ((itv->std & V4L2_STD_625_50) && !enabled) { + enabled = 1; + mode = 0x08; /* 4x3 full format */ + } + data.id = V4L2_SLICED_WSS_625; + data.field = 0; + data.line = enabled ? 23 : 0; + data.data[0] = mode & 0xff; + data.data[1] = (mode >> 8) & 0xff; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} static int odd_parity(u8 c) { diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h deleted file mode 100644 index 498e9b61c227..000000000000 --- a/drivers/media/video/ivtv/ivtv-video.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef IVTV_VIDEO_H -#define IVTV_VIDEO_H - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5); -void ivtv_video_set_io(struct ivtv *itv); - -#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bb2cbb206c14..e2288f224ab6 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -42,7 +42,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, int y_decode_height, uv_decode_height, y_size; int frame = atomic_read(&itv->yuv_info.next_fill_frame); - y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; + y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; y_decode_height = uv_decode_height = args->src.height + args->src.top; @@ -106,7 +106,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, if (itv->yuv_info.blanking_dmaptr) { dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); dma->SG_length++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 0824048ce3a2..f7215eeca018 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -32,6 +32,9 @@ #define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 #define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 +#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 +#define IVTV_YUV_UPDATE_VERTICAL 0x02 + extern const u32 yuv_offset[4]; int ivtv_yuv_filter_check(struct ivtv *itv); From fd8b281a2809d2bd9119df1fbd717ab2371297cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 10:13:15 -0300 Subject: [PATCH 137/310] V4L/DVB (6093): ivtv: reorganized and cleanup ivtv struct Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 209 ++++++++++++------------ drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 10 +- drivers/media/video/ivtv/ivtv-irq.c | 12 +- drivers/media/video/ivtv/ivtv-streams.c | 19 ++- 6 files changed, 135 insertions(+), 132 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6a74e509c87d..855697c1c968 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -667,7 +667,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) cx2341x_fill_defaults(&itv->params); itv->params.port = CX2341X_PORT_MEMORY; itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; - init_waitqueue_head(&itv->cap_w); + init_waitqueue_head(&itv->eos_waitq); init_waitqueue_head(&itv->event_waitq); init_waitqueue_head(&itv->vsync_waitq); init_waitqueue_head(&itv->dma_waitq); @@ -713,14 +713,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv) break; itv->nof_audio_inputs = i; - /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ - if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) - itv->digitizer = 0xF1; - else if (itv->card->hw_all & IVTV_HW_SAA7114) - itv->digitizer = 0xEF; - else /* cx25840 */ - itv->digitizer = 0x140; - if (itv->card->hw_all & IVTV_HW_CX25840) { itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ } else { @@ -749,6 +741,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, const struct pci_device_id *pci_id) { u16 cmd; + u8 card_rev; unsigned char pci_latency; IVTV_DEBUG_INFO("Enabling pci device\n"); @@ -795,7 +788,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, } IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); + pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev); pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && ivtv_pci_latency) { @@ -812,7 +805,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " "irq: %d, latency: %d, memory: 0x%lx\n", - itv->dev->device, itv->card_rev, dev->bus->number, + itv->dev->device, card_rev, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index b9dfdab66362..2c27515d8731 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -550,133 +550,134 @@ struct ivtv_card; /* Struct to hold info about ivtv cards */ struct ivtv { - int num; /* board number, -1 during init! */ - char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ - struct pci_dev *dev; /* PCI device */ + /* General fixed card data */ + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ + struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ - const char *card_name; /* full name of the card */ - u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ - u8 is_50hz; - u8 is_60hz; - u8 is_out_50hz; - u8 is_out_60hz; - u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ - - /* controlling Video decoder function */ + const char *card_name; /* full name of the card */ + u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ + u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* hardware description of the board */ + int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ + v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ + /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); + u32 base_addr; /* PCI resource base address */ + volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */ + volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */ + volatile void __iomem *reg_mem; /* pointer to mapped registers */ + struct ivtv_options options; /* user options */ - struct ivtv_options options; /* User options */ - int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ - struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ - int speed; - u8 speed_mute_audio; - unsigned long i_flags; /* global ivtv flags */ - atomic_t capturing; /* count number of active capture streams */ - atomic_t decoding; /* count number of active decoding streams */ - u32 irq_rr_idx; /* Round-robin stream index */ - int cur_dma_stream; /* index of stream doing DMA */ - int cur_pio_stream; /* index of stream doing PIO */ - u32 dma_data_req_offset; - u32 dma_data_req_size; - int dma_retries; - int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ - spinlock_t lock; /* lock access to this struct */ - int search_pack_header; - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - struct mutex serialize_lock; /* lock used to serialize starting streams */ + /* High-level state info */ + unsigned long i_flags; /* global ivtv flags */ + u8 is_50hz; /* 1 if the current capture standard is 50 Hz */ + u8 is_60hz /* 1 if the current capture standard is 60 Hz */; + u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */; + u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */; + int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */ + u32 audio_input; /* current audio input */ + u32 active_input; /* current video input */ + u32 active_output; /* current video output */ + v4l2_std_id std; /* current capture TV standard */ + v4l2_std_id std_out; /* current TV output standard */ + u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ + u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ + struct cx2341x_mpeg_params params; /* current encoder parameters */ - /* User based DMA for OSD */ - struct ivtv_user_dma udma; - int open_id; /* incremented each time an open occurs, used as unique ID. - starts at 1, so 0 can be used as uninitialized value - in the stream->id. */ + /* Locking */ + spinlock_t lock; /* lock access to this struct */ + /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct mutex serialize_lock; - u32 base_addr; - u32 irqmask; - struct v4l2_prio_state prio; - struct workqueue_struct *irq_work_queues; - struct work_struct irq_work_queue; - struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ + /* Streams */ + int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ + struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ + atomic_t capturing; /* count number of active capture streams */ + atomic_t decoding; /* count number of active decoding streams */ - struct vbi_info vbi; - struct ivtv_mailbox_data enc_mbox; - struct ivtv_mailbox_data dec_mbox; - struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ + /* Interrupts & DMA */ + u32 irqmask; /* active interrupts */ + u32 irq_rr_idx; /* round-robin stream index */ + struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ + struct work_struct irq_work_queue; /* work entry */ + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ + int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ + u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */ + u32 dma_data_req_size; /* store size of current DMA request */ + int dma_retries; /* current DMA retry attempt */ + struct ivtv_user_dma udma; /* user based DMA for OSD */ + struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ + u32 last_vsync_frame; /* last seen vsync field */ + wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ + wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ + wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ + wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */ - u8 card_rev; - volatile void __iomem *enc_mem, *dec_mem, *reg_mem; - u32 pgm_info_offset; - u32 pgm_info_num; - u32 pgm_info_write_idx; - u32 pgm_info_read_idx; - struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; + /* Mailbox */ + struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */ + struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */ + struct ivtv_api_cache api_cache[256]; /* cached API commands */ - u64 mpg_data_received; - u64 vbi_data_inserted; - wait_queue_head_t cap_w; - /* when the next decoder event arrives this queue is woken up */ - wait_queue_head_t event_waitq; - /* when the next decoder vsync arrives this queue is woken up */ - wait_queue_head_t vsync_waitq; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; - - /* OSD support */ - unsigned long osd_video_pbase; - int osd_global_alpha_state; /* 0=off : 1=on */ - int osd_local_alpha_state; /* 0=off : 1=on */ - int osd_color_key_state; /* 0=off : 1=on */ - u8 osd_global_alpha; /* Current global alpha */ - u32 osd_color_key; /* Current color key */ - u32 osd_pixelformat; /* Current pixel format */ - struct v4l2_rect osd_rect; /* Current OSD position and size */ - struct v4l2_rect main_rect; /* Current Main window position and size */ - - u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ - - /* i2c */ + /* I2C */ struct i2c_adapter i2c_adap; struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; - struct mutex i2c_bus_lock; - int i2c_state; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */ + int i2c_state; /* i2c bit state */ + struct mutex i2c_bus_lock; /* lock i2c bus */ - /* v4l2 and User settings */ - /* codec settings */ - struct cx2341x_mpeg_params params; - u32 audio_input; - u32 active_input; - u32 active_output; - v4l2_std_id std; - v4l2_std_id std_out; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - u8 audio_stereo_mode; - u8 audio_bilingual_mode; + /* Program Index information */ + u32 pgm_info_offset; /* start of pgm info in encoder memory */ + u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */ + u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */ + u32 pgm_info_read_idx; /* last index in pgm_info read by the application */ + struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */ - /* dualwatch */ - unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; - /* Digitizer type */ - int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ + /* Miscellaneous */ + u32 open_id; /* incremented each time an open occurs, is >= 1 */ + struct v4l2_prio_state prio; /* priority state */ + int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ + int speed; /* current playback speed setting */ + u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ + u64 mpg_data_received; /* number of bytes received from the MPEG stream */ + u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ + u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ + unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ + u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ - u32 lastVsyncFrame; - struct yuv_playback_info yuv_info; - struct osd_info *osd_info; + /* VBI state info */ + struct vbi_info vbi; /* VBI-specific data */ + + + /* YUV playback */ + struct yuv_playback_info yuv_info; /* YUV playback data */ + + + /* OSD support */ + unsigned long osd_video_pbase; + int osd_global_alpha_state; /* 1 = global alpha is on */ + int osd_local_alpha_state; /* 1 = local alpha is on */ + int osd_chroma_key_state; /* 1 = chroma-keying is on */ + u8 osd_global_alpha; /* current global alpha */ + u32 osd_chroma_key; /* current chroma key */ + u32 osd_pixelformat; /* current pixel format */ + struct v4l2_rect osd_rect; /* current OSD position and size */ + struct v4l2_rect main_rect; /* current Main window position and size */ + struct osd_info *osd_info; /* ivtv-fb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 2c521d1bb057..f5ed2cf1cd87 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->lastVsyncFrame; + vblank.count = itv->last_vsync_frame; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f4f56a6e1f81..01215a1c4b82 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -163,7 +163,7 @@ void ivtv_set_osd_alpha(struct ivtv *itv) { ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); - ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); + ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); } int ivtv_set_speed(struct ivtv *itv, int speed) @@ -426,7 +426,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_color_key; + fmt->fmt.win.chromakey = itv->osd_chroma_key; fmt->fmt.win.global_alpha = itv->osd_global_alpha; break; @@ -546,7 +546,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; if (set_fmt) { - itv->osd_color_key = fmt->fmt.win.chromakey; + itv->osd_chroma_key = fmt->fmt.win.chromakey; itv->osd_global_alpha = fmt->fmt.win.global_alpha; ivtv_set_osd_alpha(itv); } @@ -1197,7 +1197,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; if (itv->osd_local_alpha_state) fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - if (itv->osd_color_key_state) + if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; break; } @@ -1209,7 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; - itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index b6a94a1ad19b..4ec3df58e247 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->lastVsyncFrame & 1)) { + if (frame != (itv->last_vsync_frame & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->lastVsyncFrame += 1; + itv->last_vsync_frame += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; @@ -888,7 +888,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) if (combo & IVTV_IRQ_ENC_EOS) { IVTV_DEBUG_IRQ("ENC EOS\n"); set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->cap_w); + wake_up(&itv->eos_waitq); } if (combo & IVTV_IRQ_DEC_DATA_REQ) { diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 3939a804f043..e05af62a8cd5 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -404,8 +404,8 @@ static void ivtv_vbi_setup(struct ivtv *itv) if (!itv->vbi.fpi) itv->vbi.fpi = 1; - IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", - itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); + IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", + itv->vbi.enc_start, data[1], itv->vbi.fpi); /* select VBI lines. Note that the sliced argument seems to have no effect. */ @@ -494,6 +494,8 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); if (atomic_read(&itv->capturing) == 0) { + int digitizer; + /* Always use frame based mode. Experiments have demonstrated that byte stream based mode results in dropped frames and corruption. Not often, but occasionally. Many thanks go to Leonard Orb who spent a lot of @@ -519,7 +521,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); + if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) + digitizer = 0xF1; + else if (itv->card->hw_all & IVTV_HW_SAA7114) + digitizer = 0xEF; + else /* cx25840 */ + digitizer = 0x140; + + ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer); /* Setup VBI */ if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { @@ -761,7 +770,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) unsigned long duration; then = jiffies; - add_wait_queue(&itv->cap_w, &wait); + add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -787,7 +796,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); } set_current_state(TASK_RUNNING); - remove_wait_queue(&itv->cap_w, &wait); + remove_wait_queue(&itv->eos_waitq, &wait); } then = jiffies; From a158f3559334c6314c7876390caffe88c9fdb64d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 11:31:57 -0300 Subject: [PATCH 138/310] V4L/DVB (6094): ivtv: more ivtv-driver.h cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 66 +++++++++++++------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-irq.c | 10 ++-- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 2c27515d8731..332d16415ebf 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -180,11 +180,11 @@ extern int ivtv_debug; #define IVTV_MAX_PGM_INDEX (400) struct ivtv_options { - int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ - int newi2c; /* New I2C algorithm */ + int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ + int newi2c; /* new I2C algorithm */ }; /* ivtv-specific mailbox template */ @@ -231,10 +231,10 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DMA 0 /* DMA in progress */ #define IVTV_F_I_UDMA 1 /* UDMA in progress */ #define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ -#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ -#define IVTV_F_I_EOS 4 /* End of encoder stream reached */ -#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ +#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */ +#define IVTV_F_I_EOS 4 /* end of encoder stream reached */ +#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */ +#define IVTV_F_I_DIG_RST 6 /* reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ @@ -242,7 +242,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ #define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ #define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ -#define IVTV_F_I_HAVE_WORK 15 /* Used in the interrupt handler: there is work to be done */ +#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */ #define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */ #define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */ #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ @@ -295,19 +295,18 @@ struct ivtv_buffer { unsigned short b_flags; unsigned short dma_xfer_cnt; char *buf; - u32 bytesused; u32 readpos; }; struct ivtv_queue { - struct list_head list; - u32 buffers; - u32 length; - u32 bytesused; + struct list_head list; /* the list of buffers in this queue */ + u32 buffers; /* number of buffers in this queue */ + u32 length; /* total number of bytes of available buffer space */ + u32 bytesused; /* total number of bytes used in this queue */ }; -struct ivtv; /* forward reference */ +struct ivtv; /* forward reference */ struct ivtv_stream { /* These first four fields are always set, even if the stream @@ -318,11 +317,9 @@ struct ivtv_stream { int type; /* stream type */ u32 id; - spinlock_t qlock; /* locks access to the queues */ - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ u32 pending_offset; u32 pending_backup; u64 pending_pts; @@ -365,10 +362,10 @@ struct ivtv_stream { }; struct ivtv_open_id { - u32 open_id; - int type; - int yuv_frames; - enum v4l2_priority prio; + u32 open_id; /* unique ID for this file descriptor */ + int type; /* stream type */ + int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ + enum v4l2_priority prio; /* priority */ struct ivtv *itv; }; @@ -493,6 +490,14 @@ struct yuv_playback_info /* VBI data */ struct vbi_info { + /* VBI general fixed card data */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ + u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ + u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ + u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */ + u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ + u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ + u32 dec_start; u32 enc_start, enc_size; int fpi; @@ -506,12 +511,6 @@ struct vbi_info { int wss; u8 wss_found; u8 wss_no_update; - u32 raw_decoder_line_size; - u8 raw_decoder_sav_odd_field; - u8 raw_decoder_sav_even_field; - u32 sliced_decoder_line_size; - u8 sliced_decoder_sav_odd_field; - u8 sliced_decoder_sav_even_field; struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; @@ -592,8 +591,7 @@ struct ivtv { /* Locking */ spinlock_t lock; /* lock access to this struct */ - /* mutex used to serialize open/close/start/stop/ioctl operations */ - struct mutex serialize_lock; + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ /* Streams */ @@ -616,7 +614,7 @@ struct ivtv { int dma_retries; /* current DMA retry attempt */ struct ivtv_user_dma udma; /* user based DMA for OSD */ struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ - u32 last_vsync_frame; /* last seen vsync field */ + u32 last_vsync_field; /* last seen vsync field */ wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index f5ed2cf1cd87..e80564aed632 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_frame; + vblank.count = itv->last_vsync_field; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 4ec3df58e247..66d0da22389f 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->last_vsync_frame & 1)) { + if (frame != (itv->last_vsync_field & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->last_vsync_frame += 1; + itv->last_vsync_field += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; From 559e196a56a5d518181efc1d2fefe0892f4689b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 17:51:07 -0300 Subject: [PATCH 139/310] V4L/DVB (6096): ivtv: fix V4L2_ENC_CMD_STOP_AT_GOP_END support Support for V4L2_ENC_CMD_STOP_AT_GOP_END was broken. While the driver correctly waited for the card to capture until the GOP was complete, afterwards the driver buffers were just flushed instead of waiting for the application to read all the pending data. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 37 ++++++++++++++++--------- drivers/media/video/ivtv/ivtv-streams.c | 8 ++---- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 170bef61aa62..5b5d6666fa16 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -258,19 +258,19 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, } return buf; } - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } /* return if end of stream */ if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); IVTV_DEBUG_INFO("EOS %s\n", s->name); return NULL; } + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + /* wait for more data to arrive */ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); /* New buffers might have become available before we were added to the waitqueue */ @@ -378,10 +378,20 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co int rc; buf = ivtv_get_buffer(s, non_block, &rc); - if (buf == NULL && rc == -EAGAIN && tot_written) - break; - if (buf == NULL) + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + ivtv_release_stream(s); + } + /* set errno */ return rc; + } rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); if (buf != &itv->vbi.sliced_mpeg_buf) { ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); @@ -738,10 +748,11 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) ivtv_stop_v4l2_encode_stream(s, gop_end); } } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - ivtv_release_stream(s); + if (!gop_end) { + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + ivtv_release_stream(s); + } } static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index e05af62a8cd5..a3296224f821 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -719,7 +719,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) struct ivtv *itv = s->itv; DECLARE_WAITQUEUE(wait, current); int cap_type; - unsigned long then; int stopmode; if (s->v4l2dev == NULL) @@ -762,14 +761,12 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - then = jiffies; - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { /* only run these if we're shutting down the last cap */ unsigned long duration; + unsigned long then = jiffies; - then = jiffies; add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -797,10 +794,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } set_current_state(TASK_RUNNING); remove_wait_queue(&itv->eos_waitq, &wait); + set_bit(IVTV_F_S_STREAMOFF, &s->s_flags); } - then = jiffies; - /* Handle any pending interrupts */ ivtv_msleep_timeout(100, 1); } From 2d4d5f11ecf6df6974579c70461866932f0bd722 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 21:15:24 -0300 Subject: [PATCH 140/310] V4L/DVB (6097): ivtv: set correct pixel format and alpha properties ivtv: set correct pixel format and alpha properties in VIDIOC_G_FBUF Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/ivtv/ivtv-ioctl.c | 66 ++++++++++++++++++++------ 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 332d16415ebf..41f753c125da 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -672,7 +672,6 @@ struct ivtv { int osd_chroma_key_state; /* 1 = chroma-keying is on */ u8 osd_global_alpha; /* current global alpha */ u32 osd_chroma_key; /* current chroma key */ - u32 osd_pixelformat; /* current pixel format */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ struct osd_info *osd_info; /* ivtv-fb private OSD info */ diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 01215a1c4b82..6d24c6b9a45b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -699,6 +699,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) { struct ivtv_open_id *id = NULL; + u32 data[CX2341X_MBOX_MAX_DATA]; if (filp) id = (struct ivtv_open_id *)filp->private_data; @@ -1183,22 +1184,59 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + /* Really YUV variants */ + V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + }; memset(fb, 0, sizeof(*fb)); if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; - fb->fmt.pixelformat = itv->osd_pixelformat; + V4L2_FBUF_CAP_GLOBAL_ALPHA; + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + fb->fmt.pixelformat = pixel_format[pixfmt]; fb->fmt.width = itv->osd_rect.width; fb->fmt.height = itv->osd_rect.height; fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - if (itv->osd_local_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + pixfmt &= 7; + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + break; + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + if (itv->osd_local_alpha_state) { + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + else + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + } break; } @@ -1208,7 +1246,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; @@ -1226,7 +1265,6 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1248,28 +1286,28 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_output vidout; struct v4l2_audioout audout; int mode = itv->output_mode; - static const char * const output_modes[] = { + static const char * const output_modes[5] = { "None", "MPEG Streaming", "YUV Streaming", "YUV Frames", "Passthrough", }; - static const char * const audio_modes[] = { + static const char * const audio_modes[5] = { "Stereo", "Left", "Right", "Mono", "Swapped" }; - static const char * const alpha_mode[] = { + static const char * const alpha_mode[4] = { "None", "Global", "Local", "Global and Local" }; - static const char * const pixel_format[] = { - "RGB Indexed", + static const char * const pixel_format[16] = { + "ARGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1277,7 +1315,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", - "YUV Indexed", + "AYUV Indexed", "YUV 5:6:5", "AYUV 1:5:5:5", "AYUV 1:4:4:4", From 6327e952cd3ef5e5a49c84f794dbba72ff3c0e9c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 05:28:54 -0300 Subject: [PATCH 141/310] V4L/DVB (6098): ivtv: kzalloc() returns void pointer, no need to cast Since kzalloc() returns a void pointer, we don't need to cast the return value in drivers/media/video/ivtv/ivtv-queue.c Signed-off-by: Jesper Juhl Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index 437f134796e3..39a216713244 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_pending = kzalloc(SGsize, GFP_KERNEL); if (s->sg_pending == NULL) { IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); return -ENOMEM; } s->sg_pending_size = 0; - s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_processing = kzalloc(SGsize, GFP_KERNEL); if (s->sg_processing == NULL) { IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); kfree(s->sg_pending); @@ -219,7 +219,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s) } s->sg_processing_size = 0; - s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); if (s->sg_dma == NULL) { IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); kfree(s->sg_pending); From 71be258bd9bf41ca3060021f2ed50ad8c672a01e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 23 Aug 2007 22:33:28 -0300 Subject: [PATCH 142/310] V4L/DVB (6100): dvb_net: whitespace cleanup Clean whitespace brain-damage caused by previous patch, "Fix a warning at dvb_net" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 13e2998a4043..2117377c141d 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -795,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, } -static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int -pkt_len) +static void dvb_net_sec(struct net_device *dev, + const u8 *pkt, int pkt_len) { u8 *eth; struct sk_buff *skb; From d9bf2c037754f1493323829048d6210602712a43 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 25 Aug 2007 11:23:54 -0300 Subject: [PATCH 143/310] V4L/DVB (6102): dvb: remove some unneeded vmalloc() return value casts from av7110 vmalloc() returns void * - no need to cast it. Signed-off-by: Jesper Juhl Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/av7110_ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index aecfdeb8ec43..8b8144f77a73 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1542,7 +1542,7 @@ static int get_firmware(struct av7110* av7110) } /* check if the firmware is available */ - av7110->bin_fw = (unsigned char *) vmalloc(fw->size); + av7110->bin_fw = vmalloc(fw->size); if (NULL == av7110->bin_fw) { dprintk(1, "out of memory\n"); release_firmware(fw); diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index e8f553719bc5..5d19c402dad1 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -279,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, if (count < size) return -EINVAL; - page = (char *) vmalloc(size); + page = vmalloc(size); if (!page) return -ENOMEM; From 0c12c1bfc432477e38ba76f680be4b3f55112a8e Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:36:39 -0300 Subject: [PATCH 144/310] V4L/DVB (6103): dvb_ca_en50221: return correct error code value return correct error code value Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index b0bf21958ede..3f7479557919 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1569,7 +1569,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; - int err = 0; + int err; dprintk("%s\n", __FUNCTION__); @@ -1581,7 +1581,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) module_put(ca->pub->owner); - return 0; + return err; } From 226835d7e0a1136bce2a0b923e0832ab47450a30 Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:46:07 -0300 Subject: [PATCH 145/310] V4L/DVB (6104): dvb_ca_en50221: decrement module use count on error decrement module use count on error Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 3f7479557919..5c7bcb8393d2 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1535,8 +1535,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) return -EIO; err = dvb_generic_open(inode, file); - if (err < 0) + if (err < 0) { + module_put(ca->pub->owner); return err; + } for (i = 0; i < ca->slot_count; i++) { From 48136e1e93195b56dc3d9b0730917241b3365633 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:00:23 -0300 Subject: [PATCH 146/310] V4L/DVB (6105): dvb_frontend: ts_bus_ctrl() handling fixed ts_bus_ctrl() should only be called by - the first open - the last release call. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 38 +++++++++++++---------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 880d499cd36a..07c0db2abfbc 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1056,18 +1056,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dprintk ("%s\n", __FUNCTION__); - if ((ret = dvb_generic_open (inode, file)) < 0) - return ret; - - if (fe->ops.ts_bus_ctrl) { - if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) { - dvb_generic_release (inode, file); + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { + if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) return ret; - } } - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if ((ret = dvb_generic_open (inode, file)) < 0) + goto err1; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { /* normal tune mode when opened R/W */ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; fepriv->tone = -1; @@ -1075,13 +1072,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ret = dvb_frontend_start (fe); if (ret) - dvb_generic_release (inode, file); + goto err2; /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; } return ret; + +err2: + dvb_generic_release(inode, file); +err1: + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); + return ret; } static int dvb_frontend_release(struct inode *inode, struct file *file) @@ -1096,16 +1100,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) != O_RDONLY) fepriv->release_jiffies = jiffies; - if (fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl (fe, 0); - ret = dvb_generic_release (inode, file); - if (dvbdev->users==-1 && fepriv->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); + if (dvbdev->users == -1) { + if (fepriv->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + if (fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); } + return ret; } From 849be2cdf11eef830ec2a3f916c8e7d1e51bc9fb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:22:16 -0300 Subject: [PATCH 147/310] V4L/DVB (6106): dvb_frontend: Default for dvb_shutdown_timeout set to 0 Default for dvb_shutdown_timeout set to 0. dvb_shutdown_timeout > 0 is used for debugging only. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 07c0db2abfbc..32017f62a82f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,7 +42,7 @@ #include "dvbdev.h" static int dvb_frontend_debug; -static int dvb_shutdown_timeout = 5; +static int dvb_shutdown_timeout; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; From 608f62d6ffbc21067e8b9a09f887a5d6cbfe7617 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 13:17:53 -0300 Subject: [PATCH 148/310] V4L/DVB (6107): dvb_frontend: clean-up shutdown handling Now dvb_powerdown_on_sleep controls whether - whether LNB power is turned off - whether the tuner/frontend enters sleep mode Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 32017f62a82f..b203640ef1c5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -573,10 +573,9 @@ restart: dvb_frontend_swzigzag(fe); } - if (dvb_shutdown_timeout) { - if (dvb_powerdown_on_sleep) - if (fe->ops.set_voltage) - fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (dvb_powerdown_on_sleep) { + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) From 5d05704cbe7f9c4708e0f35be13839f593441215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:16:37 -0300 Subject: [PATCH 149/310] V4L/DVB (6108): videodev2.h: add new pixel formats for the cx23415 OSD The Conexant cx23415 MPEG encoder/decoder supports some unusual pixelformats for the On-Screen Display. Add new defines to videodev2.h for these formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index ae9b24c12f6a..1f503e94eff1 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -271,6 +271,7 @@ struct v4l2_pix_format /* Pixel format FOURCC depth Description */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ @@ -280,6 +281,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P','A','L','8') /* 8 8-bit palette */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ @@ -287,6 +289,10 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y','4','4','4') /* 16 xxxxyyyy uuuuvvvv */ +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y','U','V','O') /* 16 YUV-5-5-5 */ +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y','U','V','P') /* 16 YUV-5-6-5 */ +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y','U','V','4') /* 32 YUV-8-8-8-8 */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ @@ -298,7 +304,6 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ From 3eaeef57423b5f9571e7524373ec079f583b2113 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:19:18 -0300 Subject: [PATCH 150/310] V4L/DVB (6109): ivtv: use new videodev2.h pixel formats Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 6d24c6b9a45b..206eee7542db 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1186,7 +1186,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_framebuffer *fb = arg; int pixfmt; static u32 pixel_format[16] = { - V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_RGB444, @@ -1194,12 +1194,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void 0, 0, 0, - /* Really YUV variants */ - V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, 0, 0, 0, From f58db9590fc56fe519d6919abae7a70ec17b4d0e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 12:05:18 -0300 Subject: [PATCH 151/310] V4L/DVB (6111): Fix a warning when compiling on x86_64 tcm825x.c: In function 'ioctl_try_fmt_cap': tcm825x.c:639: warning: format '%d' expects type 'int', but argument 4 has type 'long unsigned int' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 4b973b099e59..3a139f288a9d 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -635,8 +635,8 @@ static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_pix_format *pix = &f->fmt.pix; isize = tcm825x_find_size(s, pix->width, pix->height); - dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", - isize, TCM825X_NUM_CAPTURE_FORMATS); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n", + isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS); pix->width = tcm825x_sizes[isize].width; pix->height = tcm825x_sizes[isize].height; From 21340ae03a61bded62acb582264660e61c0636b9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:53:16 -0300 Subject: [PATCH 152/310] V4L/DVB (6112): cx25840: use a workqueue to load the firmware Loading the firmware using the i2c bit-banging code blocks the kernel. Move the firmware load code into a workqueue so that it plays well with other processes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 45 +++++++++++++++++----- drivers/media/video/cx25840/cx25840-core.h | 4 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index ae90d1c3d12b..d6f8b3b6af40 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,9 +179,18 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } +static void cx25840_work_handler(struct work_struct *work) +{ + struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); + wake_up(&state->fw_wait); +} + static void cx25840_initialize(struct i2c_client *client) { + DEFINE_WAIT(wait); struct cx25840_state *state = i2c_get_clientdata(client); + struct workqueue_struct *q; /* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */ @@ -197,7 +206,19 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - cx25840_loadfw(client); + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -872,17 +893,16 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return 0; - state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); - if (state == 0) + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) return -ENOMEM; - client = &state->c; client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_cx25840; snprintf(client->name, sizeof(client->name) - 1, "cx25840"); - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1); + v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); @@ -891,26 +911,32 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, * 0x83 for the cx2583x and 0x84 for the cx2584x */ if ((device_id & 0xff00) == 0x8300) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - state->is_cx25836 = 1; } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - state->is_cx25836 = 0; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(state); + kfree(client); return 0; } + state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + /* Note: revision '(device_id & 0x0f) == 2' was never built. The marking skips from 0x1 == 22 to 0x3 == 23. */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), - address << 1, adapter->name); + client->addr << 1, client->adapter->name); i2c_set_clientdata(client, state); + state->c = client; + state->is_cx25836 = ((device_id & 0xff00) == 0x8300); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -944,6 +970,7 @@ static int cx25840_detach_client(struct i2c_client *client) } kfree(state); + kfree(client); return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 86e2edfc4941..ea669b1f084d 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -35,7 +35,7 @@ extern int cx25840_debug; #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) struct cx25840_state { - struct i2c_client c; + struct i2c_client *c; int pvr150_workaround; int radio; enum cx25840_video_input vid_input; @@ -48,6 +48,8 @@ struct cx25840_state { u32 rev; int is_cx25836; int is_initialized; + wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ + struct work_struct fw_work; /* work entry for fw load */ }; /* ----------------------------------------------------------------------- */ From 49ebf14e249734a5f64d5bdd9aaa2ddf4bcedc51 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:54:14 -0300 Subject: [PATCH 153/310] V4L/DVB (6113): ivtv: udelay for the i2c bus was set too high An udelay of 5 is sufficient for standard speed i2c busses, 10 make it too slow. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 085dc3938da7..285fca676a69 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -541,7 +541,7 @@ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { .setscl = ivtv_setscl_old, .getsda = ivtv_getsda_old, .getscl = ivtv_getscl_old, - .udelay = 10, + .udelay = 5, .timeout = 200, }; From 26e9d599561e9a964bd4d7c2be0029db8aaff852 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 05:41:52 -0300 Subject: [PATCH 154/310] V4L/DVB (6115): ivtv/ivtv-fb: improve locking to avoid initialization problems ivtv/ivtv-fb: improve locking to prevent ivtv/ivtv-fb initialization problems Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ drivers/media/video/ivtv/ivtv-fb.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 855697c1c968..2a5e0facca7d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1003,6 +1003,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); + mutex_lock(&itv->serialize_lock); + /* PCI Device Setup */ if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { if (retval == -EIO) @@ -1174,6 +1176,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } + mutex_unlock(&itv->serialize_lock); IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; @@ -1192,6 +1195,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); free_workqueue: destroy_workqueue(itv->irq_work_queues); + mutex_unlock(&itv->serialize_lock); err: if (retval == 0) retval = -ENODEV; diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index e80564aed632..ffe6478682ae 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1011,10 +1011,13 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); IVTV_FB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } + mutex_unlock(&itv->serialize_lock); ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); From 2f3a98931f51be6093df7c6cc2633bf238778b7d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 14:11:23 -0300 Subject: [PATCH 155/310] V4L/DVB (6116): ivtv: VBI cleanups and fixes Besides some VBI cleanups this patch also fixes a subtle problem with the VBI re-insertion stream where the PIO work handler wasn't called quickly enough, resulting in occasional corrupt data. Furthermore the CC output didn't disable CC correctly and at the right time, causing duplicates to be sent. An saa7127 fix for VPS output was also added: the wrong data was sent. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 26 ++- drivers/media/video/ivtv/ivtv-fileops.c | 11 +- drivers/media/video/ivtv/ivtv-irq.c | 10 +- drivers/media/video/ivtv/ivtv-vbi.c | 237 ++++++++---------------- drivers/media/video/ivtv/ivtv-vbi.h | 4 +- drivers/media/video/saa7127.c | 10 +- 6 files changed, 112 insertions(+), 186 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 41f753c125da..748ef66bd945 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -489,6 +489,15 @@ struct yuv_playback_info #define IVTV_VBI_FRAMES 32 /* VBI data */ +struct vbi_cc { + u8 odd[2]; /* two-byte payload of odd field */ + u8 even[2]; /* two-byte payload of even field */; +}; + +struct vbi_vps { + u8 data[5]; /* five-byte VPS payload */ +}; + struct vbi_info { /* VBI general fixed card data */ u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ @@ -502,15 +511,14 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u8 cc_data_odd[256]; - u8 cc_data_even[256]; - int cc_pos; - u8 cc_no_update; - u8 vps[5]; - u8 vps_found; - int wss; - u8 wss_found; - u8 wss_no_update; + struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to + prevent dropping CC data if they couldn't be + processed fast enough. */ + int cc_payload_idx; /* Index in cc_payload */ + u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ + int wss_payload; /* Sliced VBI WSS payload */ + u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 5b5d6666fa16..da50fa4a72a5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -563,8 +563,11 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c /* This stream does not need to start any decoding */ if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { + int elems = count / sizeof(struct v4l2_sliced_vbi_data); + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return ivtv_write_vbi(itv, user_buf, count); + ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems); + return elems * sizeof(struct v4l2_sliced_vbi_data); } mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; @@ -828,10 +831,10 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); /* If all output streams are closed, and if the user doesn't have - IVTV_DEC_STREAM_TYPE_VOUT open, then disable VBI on TV-out. */ + IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { - /* disable VBI on TV-out */ - ivtv_disable_vbi(itv); + /* disable CC on TV-out */ + ivtv_disable_cc(itv); } } else { ivtv_stop_capture(id, 0); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 66d0da22389f..bf7d99c6ffaf 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -786,7 +786,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) wake_up(&s->waitq); /* Send VBI to saa7127 */ - if (frame) { + if (frame && (itv->output_mode == OUT_PASSTHROUGH || + test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } @@ -809,7 +812,7 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) +#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) irqreturn_t ivtv_irq_handler(int irq, void *dev_id) { @@ -942,8 +945,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } } - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) + if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { queue_work(itv->irq_work_queues, &itv->irq_work_queue); + } spin_unlock(&itv->dma_reg_lock); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 5d8a40f3d2b6..c151bcf5519a 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -23,8 +23,7 @@ #include "ivtv-queue.h" #include "ivtv-vbi.h" -static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) +static void ivtv_set_vps(struct ivtv *itv, int enabled) { struct v4l2_sliced_vbi_data data; @@ -33,15 +32,15 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps data.id = V4L2_SLICED_VPS; data.field = 0; data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; + data.data[2] = itv->vbi.vps_payload.data[0]; + data.data[8] = itv->vbi.vps_payload.data[1]; + data.data[9] = itv->vbi.vps_payload.data[2]; + data.data[10] = itv->vbi.vps_payload.data[3]; + data.data[11] = itv->vbi.vps_payload.data[4]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } -static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc) { struct v4l2_sliced_vbi_data data; @@ -50,13 +49,13 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 c data.id = V4L2_SLICED_CAPTION_525; data.field = 0; data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; + data.data[0] = cc->odd[0]; + data.data[1] = cc->odd[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); data.field = 1; data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; + data.data[0] = cc->even[0]; + data.data[1] = cc->even[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } @@ -92,62 +91,50 @@ static int odd_parity(u8 c) return c & 1; } -static void passthrough_vbi_data(struct ivtv *itv, int cnt) +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt) { - int wss = 0; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - u8 vps[13]; + struct vbi_info *vi = &itv->vbi; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; int found_cc = 0; - int found_wss = 0; - int found_vps = 0; - int cc_pos = itv->vbi.cc_pos; - int i; + size_t i; for (i = 0; i < cnt; i++) { - struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; + const struct v4l2_sliced_vbi_data *d = sliced + i; if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { - found_cc = 1; if (d->field) { - cc[2] = d->data[0]; - cc[3] = d->data[1]; + cc.even[0] = d->data[0]; + cc.even[1] = d->data[1]; } else { - cc[0] = d->data[0]; - cc[1] = d->data[1]; + cc.odd[0] = d->data[0]; + cc.odd[1] = d->data[1]; } + found_cc = 1; } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { - memcpy(vps, d->data, sizeof(vps)); - found_vps = 1; + struct vbi_vps vps; + + vps.data[0] = d->data[2]; + vps.data[1] = d->data[8]; + vps.data[2] = d->data[9]; + vps.data[3] = d->data[10]; + vps.data[4] = d->data[11]; + if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) { + vi->vps_payload = vps; + set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + } } else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { - wss = d->data[0] | d->data[1] << 8; - found_wss = 1; + int wss = d->data[0] | d->data[1] << 8; + + if (vi->wss_payload != wss) { + vi->wss_payload = wss; + set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); + } } } - - if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { - itv->vbi.wss = wss; - itv->vbi.wss_found = found_wss; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - - if (found_vps || itv->vbi.vps_found) { - itv->vbi.vps[0] = vps[2]; - itv->vbi.vps[1] = vps[8]; - itv->vbi.vps[2] = vps[9]; - itv->vbi.vps[3] = vps[10]; - itv->vbi.vps[4] = vps[11]; - itv->vbi.vps_found = found_vps; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; + if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) { + vi->cc_payload[vi->cc_payload_idx++] = cc; set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); } } @@ -271,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) return line * sizeof(itv->vbi.sliced_dec_data[0]); } -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) -{ - /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ - const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - int found_cc = 0; - int cc_pos = itv->vbi.cc_pos; - - while (count >= sizeof(struct v4l2_sliced_vbi_data)) { - switch (p->id) { - case V4L2_SLICED_CAPTION_525: - if (p->line == 21) { - found_cc = 1; - if (p->field) { - cc[2] = p->data[0]; - cc[3] = p->data[1]; - } else { - cc[0] = p->data[0]; - cc[1] = p->data[1]; - } - } - break; - - case V4L2_SLICED_VPS: - if (p->line == 16 && p->field == 0) { - itv->vbi.vps[0] = p->data[2]; - itv->vbi.vps[1] = p->data[8]; - itv->vbi.vps[2] = p->data[9]; - itv->vbi.vps[3] = p->data[10]; - itv->vbi.vps[4] = p->data[11]; - itv->vbi.vps_found = 1; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - break; - - case V4L2_SLICED_WSS_625: - if (p->line == 23 && p->field == 0) { - /* No lock needed for WSS */ - itv->vbi.wss = p->data[0] | (p->data[1] << 8); - itv->vbi.wss_found = 1; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - break; - - default: - break; - } - count -= sizeof(*p); - p++; - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } - - return (const char __user *)p - ubuf; -} - /* Compress raw VBI format, removes leading SAV codes and surplus space after the field. Returns new compressed size. */ @@ -482,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); buf->bytesused = cnt; - passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); + ivtv_write_vbi(itv, itv->vbi.sliced_dec_data, + cnt / sizeof(itv->vbi.sliced_dec_data[0])); return; } } -void ivtv_disable_vbi(struct ivtv *itv) +void ivtv_disable_cc(struct ivtv *itv) { - clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_wss(itv, 0, 0); - ivtv_set_cc(itv, 0, 0, 0, 0, 0); - ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); - itv->vbi.vps_found = itv->vbi.wss_found = 0; - itv->vbi.wss = 0; - itv->vbi.cc_pos = 0; + ivtv_set_cc(itv, 0, &cc); + itv->vbi.cc_payload_idx = 0; } void ivtv_vbi_work_handler(struct ivtv *itv) { + struct vbi_info *vi = &itv->vbi; struct v4l2_sliced_vbi_data data; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; /* Lock */ if (itv->output_mode == OUT_PASSTHROUGH) { - /* Note: currently only the saa7115 is used in a PVR350, - so these commands are for now saa7115 specific. */ if (itv->is_50hz) { data.id = V4L2_SLICED_WSS_625; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { ivtv_set_wss(itv, 1, data.data[0] & 0xf); - itv->vbi.wss_no_update = 0; - } else if (itv->vbi.wss_no_update == 4) { + vi->wss_missing_cnt = 0; + } else if (vi->wss_missing_cnt == 4) { ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ } else { - itv->vbi.wss_no_update++; + vi->wss_missing_cnt++; } } else { - u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; int mode = 0; data.id = V4L2_SLICED_CAPTION_525; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 1; - c1 = data.data[0]; - c2 = data.data[1]; + cc.odd[0] = data.data[0]; + cc.odd[1] = data.data[1]; } data.field = 1; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 2; - c3 = data.data[0]; - c4 = data.data[1]; + cc.even[0] = data.data[0]; + cc.even[1] = data.data[1]; } if (mode) { - itv->vbi.cc_no_update = 0; - ivtv_set_cc(itv, mode, c1, c2, c3, c4); - } else if (itv->vbi.cc_no_update == 4) { - ivtv_set_cc(itv, 0, 0, 0, 0, 0); + vi->cc_missing_cnt = 0; + ivtv_set_cc(itv, mode, &cc); + } else if (vi->cc_missing_cnt == 4) { + ivtv_set_cc(itv, 0, &cc); } else { - itv->vbi.cc_no_update++; + vi->cc_missing_cnt++; } } return; } if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { - /* Lock */ - ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); + ivtv_set_wss(itv, 1, vi->wss_payload & 0xf); } - if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { - if (itv->vbi.cc_pos == 0) { - ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); + if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { + if (vi->cc_payload_idx == 0) { + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); } - while (itv->vbi.cc_pos) { - u8 cc_odd0 = itv->vbi.cc_data_odd[0]; - u8 cc_odd1 = itv->vbi.cc_data_odd[1]; - u8 cc_even0 = itv->vbi.cc_data_even[0]; - u8 cc_even1 = itv->vbi.cc_data_even[1]; + while (vi->cc_payload_idx) { + cc = vi->cc_payload[0]; - memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); - memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); - itv->vbi.cc_pos -= 2; - if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) + memcpy(vi->cc_payload, vi->cc_payload + 1, + sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0])); + vi->cc_payload_idx--; + if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80) continue; - /* Send to Saa7127 */ - ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); - if (itv->vbi.cc_pos == 0) - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); break; } } if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { - /* Lock */ - ivtv_set_vps(itv, itv->vbi.vps_found, - itv->vbi.vps[0], itv->vbi.vps[1], - itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); + ivtv_set_vps(itv, 1); } } diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index d5740493a690..970567b9194d 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -20,11 +20,11 @@ #ifndef IVTV_VBI_H #define IVTV_VBI_H -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); int ivtv_used_line(struct ivtv *itv, int line, int field); -void ivtv_disable_vbi(struct ivtv *itv); +void ivtv_disable_cc(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 9f986930490f..e35ef321ec71 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -332,11 +332,11 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (!enable) return 0; - state->vps_data[0] = data->data[4]; - state->vps_data[1] = data->data[10]; - state->vps_data[2] = data->data[11]; - state->vps_data[3] = data->data[12]; - state->vps_data[4] = data->data[13]; + state->vps_data[0] = data->data[2]; + state->vps_data[1] = data->data[8]; + state->vps_data[2] = data->data[9]; + state->vps_data[3] = data->data[10]; + state->vps_data[4] = data->data[11]; v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n", state->vps_data[0], state->vps_data[1], state->vps_data[2], state->vps_data[3], From effa0b08633122cc63d2b7f098434d359d5767ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:09:52 -0300 Subject: [PATCH 156/310] V4L/DVB (6117): ivtv: finish VBI related cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 67 +++++++++++++++---------- drivers/media/video/ivtv/ivtv-streams.c | 10 ---- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 748ef66bd945..5400ccef4dfb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -499,7 +499,8 @@ struct vbi_vps { }; struct vbi_info { - /* VBI general fixed card data */ + /* VBI general data, does not change during streaming */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ @@ -507,27 +508,42 @@ struct vbi_info { u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ - u32 dec_start; - u32 enc_start, enc_size; - int fpi; - u32 frame; - struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to - prevent dropping CC data if they couldn't be - processed fast enough. */ - int cc_payload_idx; /* Index in cc_payload */ - u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ - int wss_payload; /* Sliced VBI WSS payload */ - u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ - struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ - struct v4l2_format in; - /* convenience pointer to sliced struct in vbi_in union */ - struct v4l2_sliced_vbi_format *sliced_in; - int insert_mpeg; + u32 start[2]; /* start of first VBI line in the odd/even fields */ + u32 count; /* number of VBI lines per field */ + u32 raw_size; /* size of raw VBI line from the digitizer */ + u32 sliced_size; /* size of sliced VBI line from the digitizer */ - /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - One for /dev/vbi0 and one for /dev/vbi8 */ - struct v4l2_sliced_vbi_data sliced_data[36]; - struct v4l2_sliced_vbi_data sliced_dec_data[36]; + u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */ + u32 enc_start; /* start in encoder memory of VBI capture buffers */ + u32 enc_size; /* size of VBI capture area */ + int fpi; /* number of VBI frames per interrupt */ + + struct v4l2_format in; /* current VBI capture format */ + struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */ + int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */ + + /* Raw VBI compatibility hack */ + + u32 frame; /* frame counter hack needed for backwards compatibility + of old VBI software */ + + /* Sliced VBI output data */ + + struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to + prevent dropping CC data if they couldn't be + processed fast enough */ + int cc_payload_idx; /* index in cc_payload */ + u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */ + int wss_payload; /* sliced VBI WSS payload */ + u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* sliced VBI VPS payload */ + + /* Sliced VBI capture data */ + + struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */ + struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */ + + /* VBI Embedding data */ /* Buffer for VBI data inserted into MPEG stream. The first byte is a dummy byte that's never used. @@ -544,12 +560,9 @@ struct vbi_info { This pointer array will allocate 2049 bytes to store each VBI frame. */ u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; - struct ivtv_buffer sliced_mpeg_buf; - u32 inserted_frame; - - u32 start[2], count; - u32 raw_size; - u32 sliced_size; + struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */ + u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data + to be inserted in the MPEG stream */ }; /* forward declaration of struct defined in ivtv-cards.h */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index a3296224f821..fd135985e70f 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -321,16 +321,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); - if (itv->is_60hz) { - itv->vbi.count = 12; - itv->vbi.start[0] = 10; - itv->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - itv->vbi.count = 18; - itv->vbi.start[0] = 6; - itv->vbi.start[1] = 318; - } - /* setup VBI registers */ itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); From 66cfaeff95d20d1377b4fa3d2c6aa7c29d832941 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 05:45:48 -0300 Subject: [PATCH 157/310] V4L/DVB (6118): ivtv-fb: add missing FBIO_WAITFORVSYNC ioctl define Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 3 +-- include/media/ivtv-fb.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index ffe6478682ae..d2b1f5d5c8b2 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +59,6 @@ #include "ivtv-driver.h" #include "ivtv-udma.h" #include "ivtv-mailbox.h" -#include /* card parameters */ static int ivtv_fb_card_id = -1; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 3b746f5e3c9e..d3a797b17280 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -29,6 +29,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif From 0f45b8c57e40cca1778b0b75daab65ca139e5bb9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:04:10 -0300 Subject: [PATCH 158/310] V4L/DVB (6119): ivtvfb: renamed ivtv-fb to ivtvfb, move header to include/linux The convention for framebuffer devices is to call them xxxfb, not xxx-fb. Conform to this. Also move the ivtvfb.h header to include/linux: it is a public header. The FBIO_WAITFORVSYNC ioctl is now also defined in the ivtvfb.h header, no more need to include matroxfb.h for just this ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/Makefile | 2 +- drivers/media/video/ivtv/{ivtv-fb.c => ivtvfb.c} | 11 +---------- include/{media/ivtv-fb.h => linux/ivtvfb.h} | 15 +++++++++++---- 4 files changed, 14 insertions(+), 16 deletions(-) rename drivers/media/video/ivtv/{ivtv-fb.c => ivtvfb.c} (99%) rename include/{media/ivtv-fb.h => linux/ivtvfb.h} (74%) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 5efacb332114..7f20c166d59f 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. -config VIDEO_IVTV_FB +config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" depends on VIDEO_IVTV && FB && EXPERIMENTAL select FB_CFB_FILLRECT diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 6998781e2b11..e8eefd96d897 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,4 +5,4 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o -obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o +obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtvfb.c similarity index 99% rename from drivers/media/video/ivtv/ivtv-fb.c rename to drivers/media/video/ivtv/ivtvfb.c index d2b1f5d5c8b2..ff721c088479 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -40,17 +40,8 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include - -#include -#include +#include #ifdef CONFIG_MTRR #include diff --git a/include/media/ivtv-fb.h b/include/linux/ivtvfb.h similarity index 74% rename from include/media/ivtv-fb.h rename to include/linux/ivtvfb.h index d3a797b17280..e980ba62ddcc 100644 --- a/include/media/ivtv-fb.h +++ b/include/linux/ivtvfb.h @@ -1,7 +1,7 @@ /* On Screen Display cx23415 Framebuffer driver - Copyright (C) 2006 Ian Armstrong + Copyright (C) 2006, 2007 Ian Armstrong This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,8 +18,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _LINUX_IVTV_FB_H -#define _LINUX_IVTV_FB_H +#ifndef __LINUX_IVTVFB_H__ +#define __LINUX_IVTVFB_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include /* Framebuffer external API */ @@ -29,7 +36,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif From 7b3a0d49e3e929b810ade38926342faca53e867d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:11:07 -0300 Subject: [PATCH 159/310] V4L/DVB (6120): ivtvfb: rename some missed ivtv-fb references to ivtvfb Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/ivtv-driver.c | 2 +- drivers/media/video/ivtv/ivtv-driver.h | 2 +- drivers/media/video/ivtv/ivtvfb.c | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 7f20c166d59f..854cc9c30ca9 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -41,4 +41,4 @@ config VIDEO_FB_IVTV homepage at . To compile this driver as a module, choose M here: the - module will be called ivtv-fb. + module will be called ivtvfb. diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2a5e0facca7d..511a66252413 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1397,7 +1397,7 @@ static void module_cleanup(void) spin_unlock(&ivtv_cards_lock); } -/* Note: These symbols are exported because they are used by the ivtv-fb +/* Note: These symbols are exported because they are used by the ivtvfb framebuffer module and an infrared module for the IR-blaster. */ EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 5400ccef4dfb..32dfc7a859fa 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -695,7 +695,7 @@ struct ivtv { u32 osd_chroma_key; /* current chroma key */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ - struct osd_info *osd_info; /* ivtv-fb private OSD info */ + struct osd_info *osd_info; /* ivtvfb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index ff721c088479..c8ca7cbbe38b 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -128,15 +128,15 @@ MODULE_LICENSE("GPL"); #define IVTV_FB_DEBUG(x, type, fmt, args...) \ do { \ if ((x) & ivtv_fb_debug) \ - printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -1143,7 +1143,7 @@ static int __init ivtvfb_init(void) int i, registered = 0; if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } @@ -1161,7 +1161,7 @@ static int __init ivtvfb_init(void) } } if (!registered) { - printk(KERN_ERR "ivtv-fb: no cards found"); + printk(KERN_ERR "ivtvfb: no cards found"); return -ENODEV; } return 0; @@ -1172,7 +1172,7 @@ static void ivtvfb_cleanup(void) struct ivtv *itv; int i; - printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; From 641ed49db6ecf6c539a5eab50a7540542377add1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 Aug 2007 03:24:31 -0300 Subject: [PATCH 160/310] V4L/DVB (6121): ivtvfb: replace ivtv_fb prefix to ivtvfb ivtvfb: replace ivtv_fb prefix to ivtvfb, change warning to info message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 168 +++++++++++++++--------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index c8ca7cbbe38b..73e46f94b45a 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -52,8 +52,8 @@ #include "ivtv-mailbox.h" /* card parameters */ -static int ivtv_fb_card_id = -1; -static int ivtv_fb_debug = 0; +static int ivtvfb_card_id = -1; +static int ivtvfb_debug = 0; static int osd_laced; static int osd_compat; static int osd_depth; @@ -62,8 +62,8 @@ static int osd_left; static int osd_yres; static int osd_xres; -module_param(ivtv_fb_card_id, int, 0444); -module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(ivtvfb_card_id, int, 0444); +module_param_named(debug,ivtvfb_debug, int, 0644); module_param(osd_laced, bool, 0444); module_param(osd_compat, bool, 0444); module_param(osd_depth, int, 0444); @@ -72,7 +72,7 @@ module_param(osd_left, int, 0444); module_param(osd_yres, int, 0444); module_param(osd_xres, int, 0444); -MODULE_PARM_DESC(ivtv_fb_card_id, +MODULE_PARM_DESC(ivtvfb_card_id, "Only use framebuffer of the specified ivtv card (0-31)\n" "\t\t\tdefault -1: initialize all available framebuffers"); @@ -122,21 +122,21 @@ MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ -#define IVTV_FB_DBGFLG_WARN (1 << 0) -#define IVTV_FB_DBGFLG_INFO (1 << 1) +#define IVTVFB_DBGFLG_WARN (1 << 0) +#define IVTVFB_DBGFLG_INFO (1 << 1) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ +#define IVTVFB_DEBUG(x, type, fmt, args...) \ do { \ - if ((x) & ivtv_fb_debug) \ + if ((x) & ivtvfb_debug) \ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) +#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -201,7 +201,7 @@ struct ivtv_osd_coords { /* ivtv API calls for framebuffer related support */ -static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, +static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase, u32 *fblength) { u32 data[CX2341X_MBOX_MAX_DATA]; @@ -213,7 +213,7 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, return rc; } -static int ivtv_fb_get_osd_coords(struct ivtv *itv, +static int ivtvfb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -230,7 +230,7 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, return 0; } -static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -245,7 +245,7 @@ static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords osd->lines, osd->x, osd->y); } -static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { int osd_height_limit = itv->is_50hz ? 576 : 480; @@ -255,13 +255,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -281,7 +281,7 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w return 0; } -static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, +static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, unsigned long ivtv_dest_addr, void __user *userbuf, int size_in_bytes) { @@ -293,7 +293,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, /* Map User DMA */ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { mutex_unlock(&itv->udma.lock); - IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " "Error with get_user_pages: %d bytes, %d pages returned\n", size_in_bytes, itv->udma.page_count); @@ -301,7 +301,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return -EIO; } - IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", size_in_bytes, itv->udma.page_count); ivtv_udma_prepare(itv); @@ -330,7 +330,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, +static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -338,34 +338,34 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Nothing to do */ if (count == 0) { - IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); return -EINVAL; } /* Check Total FB Size */ if ((dest_offset + count) > oi->video_buffer_size) { - IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", dest_offset + count, oi->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); + IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", + IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -375,7 +375,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ - return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); + return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); } static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -412,15 +412,15 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case IVTVFB_IOC_DMA_FRAME: { struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; - return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); } default: - IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; @@ -435,7 +435,7 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) struct v4l2_rect ivtv_window; int osd_mode = -1; - IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_var\n"); /* Select color space */ if (var->nonstd) /* YUV */ @@ -463,11 +463,11 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) osd_mode = IVTV_OSD_BPP_16_565; break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } /* Change osd mode if needed. @@ -491,18 +491,18 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); } /* Read the current osd info */ - ivtv_fb_get_osd_coords(itv, &ivtv_osd); + ivtvfb_get_osd_coords(itv, &ivtv_osd); /* Now set the OSD to the size we want */ ivtv_osd.pixel_stride = var->xres_virtual; ivtv_osd.lines = var->yres_virtual; ivtv_osd.x = 0; ivtv_osd.y = 0; - ivtv_fb_set_osd_coords(itv, &ivtv_osd); + ivtvfb_set_osd_coords(itv, &ivtv_osd); /* Can't seem to find the right API combo for this. Use another function which does what we need through direct register access. */ @@ -515,22 +515,22 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; - ivtv_fb_set_display_window(itv, &ivtv_window); + ivtvfb_set_display_window(itv, &ivtv_window); /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } @@ -539,7 +539,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { struct osd_info *oi = itv->osd_info; - IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); + IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); fix->smem_start = oi->video_pbase; @@ -563,7 +563,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) int osd_height_limit; u32 pixclock, hlimit, vlimit; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); /* Set base references for mode calcs. */ if (itv->is_50hz) { @@ -582,7 +582,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -633,7 +633,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } @@ -643,14 +643,14 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->yres != oi->ivtvfb_defined.yres || var->xres_virtual != oi->ivtvfb_defined.xres_virtual || var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n", var->xres, var->yres); return -EINVAL; } @@ -660,7 +660,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -670,43 +670,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -737,24 +737,24 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) else var->pixclock = pixclock; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); return _ivtvfb_check_var(var, itv); } @@ -779,7 +779,7 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); @@ -836,7 +836,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -902,7 +902,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR("Invalid osd_left - assuming default\n"); + IVTVFB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } @@ -928,7 +928,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); + IVTVFB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } @@ -980,7 +980,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Allocate color map */ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR("abort, unable to alloc cmap\n"); + IVTVFB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } @@ -988,7 +988,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); if (!oi->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); + IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1004,12 +1004,12 @@ static int ivtvfb_init_io(struct ivtv *itv) mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { mutex_unlock(&itv->serialize_lock); - IVTV_FB_ERR("Failed to initialize ivtv\n"); + IVTVFB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } mutex_unlock(&itv->serialize_lock); - ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer @@ -1020,12 +1020,12 @@ static int ivtvfb_init_io(struct ivtv *itv) oi->video_vbase = itv->dec_mem + oi->video_rbase; if (!oi->video_vbase) { - IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", oi->video_buffer_size, oi->video_pbase); return -EIO; } - IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", oi->video_pbase, oi->video_vbase, oi->video_buffer_size / 1024); @@ -1045,7 +1045,7 @@ static int ivtvfb_init_io(struct ivtv *itv) if (mtrr_add(oi->fb_start_aligned_physaddr, oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_WARN("cannot use mttr\n"); + IVTVFB_INFO("disabled mttr\n"); oi->fb_start_aligned_physaddr = 0; oi->fb_end_aligned_physaddr = 0; } @@ -1089,13 +1089,13 @@ static int ivtvfb_init_card(struct ivtv *itv) int rc; if (itv->osd_info) { - IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); return -EBUSY; } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); if (itv->osd_info == 0) { - IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } @@ -1129,7 +1129,7 @@ static int ivtvfb_init_card(struct ivtv *itv) /* Note if we're running in compatibility mode */ if (osd_compat) - IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); /* Allocate DMA */ ivtv_udma_alloc(itv); @@ -1142,20 +1142,20 @@ static int __init ivtvfb_init(void) struct ivtv *itv; int i, registered = 0; - if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } /* Locate & initialise all cards supporting an OSD. */ for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + if (ivtvfb_card_id != -1 && i != ivtvfb_card_id) continue; itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (ivtvfb_init_card(itv) == 0) { - IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i); registered++; } } @@ -1177,7 +1177,7 @@ static void ivtvfb_cleanup(void) for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { - IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i); ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); unregister_framebuffer(&itv->osd_info->ivtvfb_info); ivtvfb_release_buffers(itv); From 136280322d894e6ec07187f2427b00c3d64ad066 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 28 Aug 2007 03:28:04 -0300 Subject: [PATCH 161/310] V4L/DVB (6122): ivtvfb: fix an obvious bug in ivtvfb_release_buffers() Signed-off-by: Adrian Bunk Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 73e46f94b45a..9684048fe56c 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1064,8 +1064,8 @@ static void ivtvfb_release_buffers (struct ivtv *itv) struct osd_info *oi = itv->osd_info; /* Release cmap */ - if (oi->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len) + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ if (oi->ivtvfb_info.pseudo_palette) From 51b39dfa5477fdb2459e3c46f855f01b8b03102d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:13:04 -0300 Subject: [PATCH 162/310] V4L/DVB (6123): ivtv: move ivtv.h public header to include/linux Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 +- include/{media => linux}/ivtv.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) rename include/{media => linux}/ivtv.h (93%) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 32dfc7a859fa..3bda1df63cb6 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -62,7 +62,7 @@ #include #include -#include +#include /* Memory layout */ diff --git a/include/media/ivtv.h b/include/linux/ivtv.h similarity index 93% rename from include/media/ivtv.h rename to include/linux/ivtv.h index 412b48ea8eda..794b8daa9378 100644 --- a/include/media/ivtv.h +++ b/include/linux/ivtv.h @@ -18,8 +18,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _LINUX_IVTV_H -#define _LINUX_IVTV_H +#ifndef __LINUX_IVTV_H__ +#define __LINUX_IVTV_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include /* ivtv knows several distinct output modes: MPEG streaming, YUV streaming, YUV updates through user DMA and the passthrough From 38051450b378ef2cb51dff76a6b8299f59129172 Mon Sep 17 00:00:00 2001 From: Tyler Trafford Date: Tue, 28 Aug 2007 17:56:47 -0300 Subject: [PATCH 163/310] V4L/DVB (6124): cx25840: add a few 10 microsecond delays There were a couple of places in the cx25840 initialization where the datasheet called for a 10 microsecond delay, which we ignored because of the 10 usec I2C delay. Put them in anyway now that the I2C delay was decreased to 5 usec. Signed-off-by: Tyler Trafford Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index d6f8b3b6af40..90f7859bb48e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -133,7 +133,9 @@ static void init_dll1(struct i2c_client *client) cx25840_write(client, 0x159, 0x23); cx25840_write(client, 0x15a, 0x87); cx25840_write(client, 0x15b, 0x06); + udelay(10); cx25840_write(client, 0x159, 0xe1); + udelay(10); cx25840_write(client, 0x15a, 0x86); cx25840_write(client, 0x159, 0xe0); cx25840_write(client, 0x159, 0xe1); @@ -147,6 +149,7 @@ static void init_dll2(struct i2c_client *client) cx25840_write(client, 0x15d, 0xe3); cx25840_write(client, 0x15e, 0x86); cx25840_write(client, 0x15f, 0x06); + udelay(10); cx25840_write(client, 0x15d, 0xe1); cx25840_write(client, 0x15d, 0xe0); cx25840_write(client, 0x15d, 0xe1); @@ -165,9 +168,7 @@ static void cx25836_initialize(struct i2c_client *client) /* 3c. */ cx25840_and_or(client, 0x159, ~0x02, 0x02); /* 3d. */ - /* There should be a 10-us delay here, but since the - i2c bus already has a 10-us delay we don't need to do - anything */ + udelay(10); /* 3e. */ cx25840_and_or(client, 0x159, ~0x02, 0x00); /* 3f. */ From b930e1d851c3ffbf82127bd0e4d72ffe94d4b7f2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 18:16:54 -0300 Subject: [PATCH 164/310] V4L/DVB (6125): whitespace cleanup: replace leading spaces with tabs There were many instances of 7-space indents spread throughout the v4l-dvb tree. This patch replaces the 7-space indents with tabs. The whitespace cleaner script doesn't catch these, because it assumes that all indents are 8-space. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 6 +- drivers/media/dvb/ttpci/av7110_hw.c | 28 +++++----- drivers/media/radio/radio-terratec.c | 2 +- drivers/media/video/bt8xx/bttv-cards.c | 20 +++---- drivers/media/video/cx88/cx88-blackbird.c | 4 +- drivers/media/video/cx88/cx88-mpeg.c | 64 +++++++++++----------- drivers/media/video/cx88/cx88-tvaudio.c | 6 +- drivers/media/video/msp3400-driver.c | 10 ++-- drivers/media/video/planb.c | 30 +++++----- drivers/media/video/pwc/pwc-ctrl.c | 2 +- drivers/media/video/pwc/pwc-if.c | 4 +- drivers/media/video/saa7134/saa7134-alsa.c | 2 +- 12 files changed, 89 insertions(+), 89 deletions(-) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index b910fa0baa07..5a12b5679556 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; + unsigned int mask = 0; if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; poll_wait(file, &cinergyt2->poll_wq, wait); - if (cinergyt2->pending_fe_events != 0) + if (cinergyt2->pending_fe_events != 0) mask |= (POLLIN | POLLRDNORM | POLLPRI); mutex_unlock(&cinergyt2->sem); - return mask; + return mask; } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 515e8232e020..a468aa2e4854 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) { - int i; - int length = last - first + 1; + int i; + int length = last - first + 1; - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; - for (i = 0; i < length; i++) { - u32 color, blend, yuv; + for (i = 0; i < length; i++) { + u32 color, blend, yuv; - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 7e1911c3d54e..535ffe8c8102 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1) i--; p--; temp = temp/2; - } + } spin_lock(&lock); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 1f4f2625395e..900d18e14060 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3275,15 +3275,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input) btaor((2)<<5, ~(3<<5), BT848_IFORM); gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); - /* composite */ - /* set chroma ADC to sleep */ - btor(BT848_ADC_C_SLEEP, BT848_ADC); - /* set to composite video */ - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); } static void gvc1100_muxsel(struct bttv *btv, unsigned int input) @@ -3452,7 +3452,7 @@ void __devinit bttv_init_card2(struct bttv *btv) printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); } break; - case BTTV_BOARD_STB2: + case BTTV_BOARD_STB2: if (btv->cardid == 0x3060121a) { /* Fix up entry for 3DFX VoodooTV 100, which is an OEM STB card variant. */ @@ -3783,7 +3783,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) for (i = 12; i < 21; i++) serial *= 10, serial += ee[i] - '0'; } - } else { + } else { unsigned short type; for (i = 4*16; i < 8*16; i += 16) { diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 47007380a98a..fcaf4f51293f 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1077,7 +1077,7 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; - dev = cx8802_get_device(inode); + dev = cx8802_get_device(inode); dprintk( 1, "%s\n", __FUNCTION__); @@ -1234,7 +1234,7 @@ static struct video_device cx8802_mpeg_template = .vidioc_s_tuner = vidioc_s_tuner, .vidioc_s_std = vidioc_s_std, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 4e6a84f15d17..d302793fcfb9 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -179,43 +179,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, struct cx88_buffer *buf; struct list_head *item; - dprintk( 1, "cx8802_restart_queue\n" ); + dprintk( 1, "cx8802_restart_queue\n" ); if (list_empty(&q->active)) { - struct cx88_buffer *prev; - prev = NULL; + struct cx88_buffer *prev; + prev = NULL; - dprintk(1, "cx8802_restart_queue: queue is empty\n" ); + dprintk(1, "cx8802_restart_queue: queue is empty\n" ); - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx8802_start_dma(dev, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(1,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(1,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 82364fb07025..76e5c78d8ae4 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -798,9 +798,9 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) core->astat = reg; /* TODO - Reading from AUD_STATUS is not enough - for auto-detecting sap/dual-fm/nicam. - Add some code here later. + Reading from AUD_STATUS is not enough + for auto-detecting sap/dual-fm/nicam. + Add some code here later. */ return; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e9d400e19a5d..c0c87e06259b 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -244,17 +244,17 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val) * ----------------------------------------------------------------------- */ static int scarts[3][9] = { - /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ + /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, + { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, + { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, + { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, }; static char *scart_names[] = { - "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" + "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" }; void msp_set_scart(struct i2c_client *client, int in, int out) diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 4ab1af74a970..0ef73d9d5848 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -844,21 +844,21 @@ cmd_tab_mask_end: /*********************************/ static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 0, + PLANB_GRAY, + 0, + 0, + 0, + PLANB_COLOUR32, + PLANB_COLOUR15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, }; #define PLANB_PALETTE_MAX 15 diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 338ced7188f2..ea53316d2111 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1648,7 +1648,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ARG_OUT(cmd) break; } - /* + /* case VIDIOCPWCGVIDTABLE: { ARG_DEF(struct pwc_table_init_buffer, table); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index d3ac70a0d9ca..1088ebf5744f 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -126,9 +126,9 @@ static struct usb_driver pwc_driver = { static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_fbufs = 3; /* Default number of frame buffers */ - int pwc_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_mbufs = 2; /* Default number of mmap() buffers */ #ifdef CONFIG_USB_PWC_DEBUG - int pwc_trace = PWC_DEBUG_LEVEL; + int pwc_trace = PWC_DEBUG_LEVEL; #endif static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index eb5e77dd0d18..c6f7279669c1 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -312,7 +312,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev) dev->dmasound.blksize = 0; dev->dmasound.bufsize = 0; - return 0; + return 0; } From 293197cd0f34eb6bfb5492a63a878575b69e9df4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 28 Aug 2007 17:20:42 -0300 Subject: [PATCH 165/310] V4L/DVB (6126): tuner: add warning for obsolete i2c address range 0x64 thru 0x6f The tuner module has a rather aggressive range of possible i2c addresses. As per the specs available, it appears as if there are no 4-byte tuners that actually use i2c addresses in the range 0x64 thru 0x6f, yet, tuner-core claims the address range 0x60 thru 0x6f. Allowing tuner.ko to probe these addresses can cause potential damage to certain IR receivers, RTC chips or any other IC's that might otherwise reside on the i2c bus using one of these addresses. The plan is to remove these i2c addresses from the i2c address range of the tuner module. If any devices are discovered that actually do have tuners at one of these addresses, the newer i2c probing methods will be used to handle those cases. In order to collect this information and avoid any potential regressions, the following warning has been added upon successful detection of a tuner using an i2c address in the range 0x64 thru 0x6f: ====================== WARNING! ====================== Support for tuners in i2c address range 0x64 thru 0x6f will soon be dropped. This message indicates that your hardware has a {tuner name} tuner at i2c address {addr}. To ensure continued support for your device, please send a copy of this message, along with full dmesg output to v4l-dvb-maintainer@linuxtv.org Please use subject line: "obsolete tuner i2c address." ====================== WARNING! ====================== Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index baeae28f2836..f505f43bb126 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -145,6 +145,27 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +static void tuner_i2c_address_check(struct tuner *t) +{ + if ((t->type == UNSET || t->type == TUNER_ABSENT) || + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + return; + + tuner_warn("====================== WARNING! ======================\n"); + tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); + tuner_warn("will soon be dropped. This message indicates that your\n"); + tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", + t->i2c.name, t->i2c.addr); + tuner_warn("To ensure continued support for your device, please\n"); + tuner_warn("send a copy of this message, along with full dmesg\n"); + tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); + tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); + tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", + t->i2c.adapter->name, t->i2c.addr, t->type, + tuners[t->type].name); + tuner_warn("====================== WARNING! ======================\n"); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -244,6 +265,7 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); + tuner_i2c_address_check(t); } /* From db8a695658cda21eacfa2a5e3b15e8964bfb93ef Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:24:42 -0300 Subject: [PATCH 166/310] V4L/DVB (6127): tuner: kill i2c_client interface to tuner sub-drivers To ease the conversion of the analog tuner sub-drivers into dvb_frontend style tuner modules, we must remove the i2c_client interface. dvb_frontend style tuner modules use i2c_transfer directly on the i2c_adapter. This change only alters the interface between tuner.ko and the tuner sub-drivers. The v4l2 / i2c_client interface to tuner.ko remains intact. This patch adds inline functions tuner_i2c_xfer_send, and tuner_i2c_xfer_recv, to replace i2c_master_send and i2c_master_recv inside the tuner sub-drivers. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 138 ++++++++-------- drivers/media/video/tda8290.c | 247 +++++++++++++++-------------- drivers/media/video/tda9887.c | 39 ++--- drivers/media/video/tea5761.c | 55 ++++--- drivers/media/video/tea5767.c | 61 ++++--- drivers/media/video/tuner-core.c | 55 ++++--- drivers/media/video/tuner-driver.h | 37 +++-- drivers/media/video/tuner-i2c.h | 70 ++++++++ drivers/media/video/tuner-simple.c | 57 ++++--- 9 files changed, 430 insertions(+), 329 deletions(-) create mode 100644 drivers/media/video/tuner-i2c.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index bd495c12d29f..41bc91817a16 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -37,23 +37,22 @@ static char *microtune_part[] = { }; struct microtune_priv { + struct tuner_i2c_props i2c_props; + unsigned int xogc; unsigned int radio_if2; }; -static void microtune_release(struct i2c_client *c) +static void microtune_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } // IsSpurInBand()? -static int mt2032_spurcheck(struct i2c_client *c, +static int mt2032_spurcheck(struct tuner *t, int f1, int f2, int spectrum_from,int spectrum_to) { - struct tuner *t = i2c_get_clientdata(c); int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -81,7 +80,7 @@ static int mt2032_spurcheck(struct i2c_client *c, return 1; } -static int mt2032_compute_freq(struct i2c_client *c, +static int mt2032_compute_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -90,7 +89,6 @@ static int mt2032_compute_freq(struct i2c_client *c, int *ret_sel, unsigned int xogc) //all in Hz { - struct tuner *t = i2c_get_clientdata(c); unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -140,7 +138,7 @@ static int mt2032_compute_freq(struct i2c_client *c, return(-1); } - mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -164,16 +162,16 @@ static int mt2032_compute_freq(struct i2c_client *c, return 0; } -static int mt2032_check_lo_lock(struct i2c_client *c) +static int mt2032_check_lo_lock(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; int try,lock=0; unsigned char buf[2]; for(try=0;try<10;try++) { buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); lock=buf[0] &0x06; @@ -186,15 +184,15 @@ static int mt2032_check_lo_lock(struct i2c_client *c) return lock; } -static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int tad1; buf[0]=0x0f; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); tad1=buf[0]&0x07; @@ -217,58 +215,57 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) buf[0]=0x0f; buf[1]=sel; - i2c_master_send(c,buf,2); - lock=mt2032_check_lo_lock(c); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + lock=mt2032_check_lo_lock(t); return lock; } -static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, +static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); buf[0]=0; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; // send only the relevant registers per Rev. 1.2 buf[0]=0; - ret=i2c_master_send(c,buf,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); buf[5]=5; - ret=i2c_master_send(c,buf+5,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); buf[11]=11; - ret=i2c_master_send(c,buf+11,3); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); if(ret!=3) tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(c); + lock=mt2032_check_lo_lock(t); if(optimize_vco) - lock=mt2032_optimize_vco(c,sel,lock); + lock=mt2032_optimize_vco(t,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); buf[0]=7; buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); mdelay(10); buf[1]=8+priv->xogc; - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); } if (lock!=6) @@ -276,15 +273,14 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, buf[0]=2; buf[1]=0x20; // LOGC for optimal phase noise - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } -static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); int if2,from,to; // signal bandwidth and picture carrier @@ -300,18 +296,17 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, 1090*1000*1000, if2, from, to); } -static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq * 1000 / 16, + mt2032_set_if_freq(t, freq * 1000 / 16, 1085*1000*1000,if2,if2,if2); } @@ -322,9 +317,8 @@ static struct tuner_operations mt2032_tuner_ops = { }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) +static int mt2032_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -334,7 +328,7 @@ static int mt2032_init(struct i2c_client *c) buf[2]=0xff; buf[3]=0x0f; buf[4]=0x1f; - ret=i2c_master_send(c,buf+1,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); buf[5]=6; // Index register 6 buf[6]=0xe4; @@ -342,11 +336,11 @@ static int mt2032_init(struct i2c_client *c) buf[8]=0xc3; buf[9]=0x4e; buf[10]=0xec; - ret=i2c_master_send(c,buf+5,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); buf[12]=13; // Index register 13 buf[13]=0x32; - ret=i2c_master_send(c,buf+12,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); // Adjust XOGC (register 7), wait for XOK xogc=7; @@ -354,8 +348,8 @@ static int mt2032_init(struct i2c_client *c) tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); mdelay(10); buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); xok=buf[0]&0x01; tuner_dbg("mt2032: xok = 0x%02x\n",xok); if (xok == 1) break; @@ -368,7 +362,7 @@ static int mt2032_init(struct i2c_client *c) } buf[0]=0x07; buf[1]=0x88 + xogc; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); @@ -379,21 +373,21 @@ static int mt2032_init(struct i2c_client *c) return(1); } -static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0] = 6; buf[1] = antenna ? 0x11 : 0x10; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -449,14 +443,13 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned printk("\n"); } - ret=i2c_master_send(c,buf,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); if (ret!=6) tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); unsigned int if2; if (t->std & V4L2_STD_525_60) { @@ -470,18 +463,17 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(c, freq*62500, if2); - mt2050_set_antenna(c, tv_antenna); + mt2050_set_if_freq(t, freq*62500, if2); + mt2050_set_antenna(t, tv_antenna); } -static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; - mt2050_set_if_freq(c, freq * 1000 / 16, if2); - mt2050_set_antenna(c, radio_antenna); + mt2050_set_if_freq(t, freq * 1000 / 16, if2); + mt2050_set_antenna(t, radio_antenna); } static struct tuner_operations mt2050_tuner_ops = { @@ -490,23 +482,23 @@ static struct tuner_operations mt2050_tuner_ops = { .release = microtune_release, }; -static int mt2050_init(struct i2c_client *c) +static int mt2050_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0]=6; buf[1]=0x10; - ret=i2c_master_send(c,buf,2); // power + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power buf[0]=0x0f; buf[1]=0x0f; - ret=i2c_master_send(c,buf,2); // m1lo + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo buf[0]=0x0d; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2050: sro is %x\n",buf[0]); @@ -515,10 +507,9 @@ static int mt2050_init(struct i2c_client *c) return 0; } -int microtune_init(struct i2c_client *c) +int microtune_init(struct tuner *t) { struct microtune_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); char *name; unsigned char buf[21]; int company_code; @@ -528,6 +519,9 @@ int microtune_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); @@ -541,8 +535,8 @@ int microtune_init(struct i2c_client *c) } name = "unknown"; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); if (tuner_debug) { int i; tuner_dbg("MT20xx hexdump:"); @@ -562,10 +556,10 @@ int microtune_init(struct i2c_client *c) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(c); + mt2032_init(t); break; case MT2050: - mt2050_init(c); + mt2050_init(t); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -573,7 +567,7 @@ int microtune_init(struct i2c_client *c) return 0; } - strlcpy(c->name, name, sizeof(c->name)); + strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); tuner_info("microtune %s found, OK\n",name); return 0; } diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 760d22f65da2..beb4a7e1d286 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -26,6 +26,8 @@ /* ---------------------------------------------------------------------- */ struct tda8290_priv { + struct tuner_i2c_props i2c_props; + unsigned char tda8290_easy_mode; unsigned char tda827x_lpsel; unsigned char tda827x_addr; @@ -79,13 +81,12 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; @@ -114,54 +115,53 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) msg.buf = tuner_reg; msg.len = 8; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.buf= reg2; msg.len = 2; reg2[0] = 0x80; reg2[1] = 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0xbf; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 4; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4]; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(550); reg2[0] = 0x30; reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0x3f; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x80; reg2[1] = 0x08; // Vsync en - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct i2c_client *c) +static void tda827x_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /* ---------------------------------------------------------------------- */ @@ -204,12 +204,12 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct i2c_client *c, int high) +static void tda827xa_lna_gain(struct tuner *t, int high) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char buf[] = {0x22, 0x01}; int arg; - struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; + struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; if (t->config) { if (high) tuner_dbg("setting LNA to high gain\n"); @@ -227,29 +227,28 @@ static void tda827xa_lna_gain(struct i2c_client *c, int high) else arg = 0; if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 1, arg); + t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; if (t->config == 2) buf[1] = high ? 1 : 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 0, high); + t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[11]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - tda827xa_lna_gain( c, 1); + tda827xa_lna_gain(t, 1); msleep(10); if (t->mode == V4L2_TUNER_RADIO) @@ -278,7 +277,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[9] = 0x20; tuner_reg[10] = 0x00; msg.len = 11; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x90; tuner_reg[1] = 0xff; @@ -286,81 +285,81 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[3] = 0; tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); msg.len = 5; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xa0; tuner_reg[1] = 0xc0; msg.len = 2; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x30; tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = I2C_M_RD; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = 0; tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain( c, 0); + tda827xa_lna_gain(t, 0); msleep(100); tuner_reg[0] = 0x60; tuner_reg[1] = 0x3c; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(163); tuner_reg[0] = 0x50; tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x80; tuner_reg[1] = 0x28; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xb0; tuner_reg[1] = 0x01; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xc0; tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct i2c_client *c) +static void tda827xa_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct i2c_client *c, int close) +static void tda8290_i2c_bridge(struct tuner *t, int close) { + struct tda8290_priv *priv = t->priv; + unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; unsigned char *msg; if(close) { msg = enable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } } /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; @@ -385,34 +384,34 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) int i; tuner_dbg("tda827xa config is 0x%02x\n", t->config); - i2c_master_send(c, easy_mode, 2); - i2c_master_send(c, agc_out_on, 2); - i2c_master_send(c, soft_reset, 2); + tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); msleep(1); expert_mode[1] = priv->tda8290_easy_mode + 0x80; - i2c_master_send(c, expert_mode, 2); - i2c_master_send(c, gainset_off, 2); - i2c_master_send(c, if_agc_spd, 2); + tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); if (priv->tda8290_easy_mode & 0x60) - i2c_master_send(c, adc_head_9, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); else - i2c_master_send(c, adc_head_6, 2); - i2c_master_send(c, pll_bw_nom, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(c, ifc, freq); + tda827xa_tune(t, ifc, freq); else - tda827x_tune(c, ifc, freq); + tda827x_tune(t, ifc, freq); for (i = 0; i < 3; i++) { - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if (pll_stat & 0x80) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); break; } else { @@ -424,28 +423,28 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", agc_stat, adc_sat, pll_stat & 0x80); - i2c_master_send(c, gainset_2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(c); + tda827xa_agcf(t); else - tda827x_agcf(c); + tda827x_agcf(t); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); - i2c_master_send(c, adc_head_12, 2); - i2c_master_send(c, pll_bw_low, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); msleep(100); } } @@ -453,20 +452,20 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) /* l/ l' deadlock? */ if(priv->tda8290_easy_mode & 0x60) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((adc_sat > 20) || !(pll_stat & 0x80)) { tuner_dbg("trying to resolve SECAM L deadlock\n"); - i2c_master_send(c, agc_rst_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); msleep(40); - i2c_master_send(c, agc_rst_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); } } - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, if_agc_set, 2); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); return 0; } @@ -515,69 +514,69 @@ static void set_audio(struct tuner *t) tuner_dbg("setting tda8290 to system %s\n", mode); } -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; set_audio(t); - tda8290_tune(c, priv->sgIF, freq); + tda8290_tune(t, priv->sgIF, freq); } -static void set_radio_freq(struct i2c_client *c, unsigned int freq) +static void set_radio_freq(struct tuner *t, unsigned int freq) { /* if frequency is 5.5 MHz */ - tda8290_tune(c, 88, freq); + tda8290_tune(t, 88, freq); } -static int has_signal(struct i2c_client *c) +static int has_signal(struct tuner *t) { + struct tda8290_priv *priv = t->priv; + unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; - i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - i2c_master_recv(c, &afc, 1); + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static void standby(struct i2c_client *c) +static void standby(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, tda8290_agc_tri, 2); - i2c_master_send(c, tda8290_standby, 2); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } -static void tda8290_init_if(struct i2c_client *c) +static void tda8290_init_if(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; + unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; if ((t->config == 1) || (t->config == 2)) - i2c_master_send(c, set_GP00_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else - i2c_master_send(c, set_GP01_CF, 2); - i2c_master_send(c, set_VS, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct i2c_client *c) +static void tda8290_init_tuner(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; @@ -588,17 +587,15 @@ static void tda8290_init_tuner(struct i2c_client *c) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(c, 1); - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct i2c_client *c) +static void tda8290_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -611,10 +608,9 @@ static struct tuner_operations tda8290_tuner_ops = { .release = tda8290_release, }; -int tda8290_init(struct i2c_client *c) +int tda8290_init(struct tuner *t) { struct tda8290_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); u8 data; int i, ret, tuners_found; u32 tuner_addrs; @@ -625,13 +621,16 @@ int tda8290_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; - tda8290_i2c_bridge(c, 1); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + tda8290_i2c_bridge(t, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; for (i=0x60; i<= 0x63; i++) { msg.addr = i; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { tuners_found++; tuner_addrs = (tuner_addrs << 8) + i; @@ -641,11 +640,11 @@ int tda8290_init(struct i2c_client *c) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if(ret == 1) tuner_addrs = tuner_addrs >> 8; else @@ -662,31 +661,33 @@ int tda8290_init(struct i2c_client *c) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(c, 1); - ret = i2c_transfer(c->adapter, &msg, 1); + tda8290_i2c_bridge(t, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) tuner_warn ("TDA827x access failed!\n"); if ((data & 0x3c) == 0) { - strlcpy(c->name, "tda8290+75", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); priv->tda827x_ver = 0; } else { - strlcpy(c->name, "tda8290+75a", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", c->name); + tuner_info("type set to %s\n", t->i2c.name); memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(c); - tda8290_init_if(c); + tda8290_init_tuner(t); + tda8290_init_if(t); return 0; } -int tda8290_probe(struct i2c_client *c) +int tda8290_probe(struct tuner *t) { + struct i2c_client *c = &t->i2c; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; unsigned char easy_mode_g[] = { 0x01, 0x04 }; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d162bc67d445..be5387f11afb 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -29,6 +29,8 @@ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) struct tda9887_priv { + struct tuner_i2c_props i2c_props; + unsigned char data[4]; }; @@ -510,19 +512,19 @@ static int tda9887_set_config(struct tuner *t, char *buf) static int tda9887_status(struct tuner *t) { + struct tda9887_priv *priv = t->priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); - if (1 != (rc = i2c_master_recv(&t->i2c,buf,1))) + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); dump_read_message(t, buf); return 0; } -static void tda9887_configure(struct i2c_client *client) +static void tda9887_configure(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; int rc; @@ -557,7 +559,7 @@ static void tda9887_configure(struct i2c_client *client) if (tuner_debug > 1) dump_write_message(t, priv->data); - if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (tuner_debug > 2) { @@ -568,16 +570,15 @@ static void tda9887_configure(struct i2c_client *client) /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct i2c_client *client) +static void tda9887_tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct i2c_client *client) +static int tda9887_get_afc(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); + struct tda9887_priv *priv = t->priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -587,26 +588,24 @@ static int tda9887_get_afc(struct i2c_client *client) int afc=0; __u8 reg = 0; - if (1 == i2c_master_recv(&t->i2c,®,1)) + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; return afc; } -static void tda9887_standby(struct i2c_client *client) +static void tda9887_standby(struct tuner *t) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_set_freq(struct i2c_client *client, unsigned int freq) +static void tda9887_set_freq(struct tuner *t, unsigned int freq) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_release(struct i2c_client *c) +static void tda9887_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -620,17 +619,19 @@ static struct tuner_operations tda9887_tuner_ops = { .release = tda9887_release, }; -int tda9887_tuner_init(struct i2c_client *c) +int tda9887_tuner_init(struct tuner *t) { struct tda9887_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; t->priv = priv; - strlcpy(c->name, "tda9887", sizeof(c->name)); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, t->i2c.driver->driver.name); diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 43bdc374927e..9965ba48cffa 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,6 +18,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5761_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /*************************** @@ -114,10 +118,8 @@ extern int tuner_debug; /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -135,9 +137,9 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; @@ -167,31 +169,31 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) if (tuner_debug) tea5761_status_dump(buffer); - if (7 != (rc = i2c_master_send(c, buffer, 7))) + if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -static int tea5761_signal(struct i2c_client *c) +static int tea5761_signal(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct i2c_client *c) +static int tea5761_stereo(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[9] & TEA5761_TUNCHECK_STEREO; @@ -201,13 +203,13 @@ static int tea5761_stereo(struct i2c_client *c) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct i2c_client *c) +int tea5761_autodetection(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; - if (16 != (rc = i2c_master_recv(c, buffer, 16))) { + if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } @@ -220,22 +222,37 @@ int tea5761_autodetection(struct i2c_client *c) return 0; } +static void tea5761_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5761_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5761_signal, .is_stereo = tea5761_stereo, + .release = tea5761_release, }; -int tea5761_tuner_init(struct i2c_client *c) +int tea5761_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(c) == EINVAL) + if (tea5761_autodetection(t) == EINVAL) return EINVAL; + priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(c->name, "tea5761", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4c9c4e01331a..5a08ec2f99fb 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,6 +20,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /****************************** @@ -129,10 +133,8 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -190,9 +192,9 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned char buffer[5]; unsigned div; int rc; @@ -246,38 +248,38 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) buffer[0] = (div >> 8) & 0x3f; buffer[1] = div & 0xff; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); if (tuner_debug) { - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } } -static int tea5767_signal(struct i2c_client *c) +static int tea5767_signal(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct i2c_client *c) +static int tea5767_stereo(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[2] & TEA5767_STEREO_MASK; @@ -287,10 +289,10 @@ static int tea5767_stereo(struct i2c_client *c) return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct i2c_client *c) +static void tea5767_standby(struct tuner *t) { unsigned char buffer[5]; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -301,17 +303,17 @@ static void tea5767_standby(struct i2c_client *c) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; buffer[4] = 0; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -int tea5767_autodetection(struct i2c_client *c) +int tea5767_autodetection(struct tuner *t) { + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - struct tuner *t = i2c_get_clientdata(c); - if ((rc = i2c_master_recv(c, buffer, 7))< 5) { + if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } @@ -343,20 +345,35 @@ int tea5767_autodetection(struct i2c_client *c) return 0; } +static void tea5767_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5767_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5767_signal, .is_stereo = tea5767_stereo, .standby = tea5767_standby, + .release = tea5767_release, }; -int tea5767_tuner_init(struct i2c_client *c) +int tea5767_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(c->name, "tea5767", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f505f43bb126..0363eae800e7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -94,7 +94,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(c, freq); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -121,7 +121,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(c, freq); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -199,7 +199,7 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if (t->ops.release) - t->ops.release(c); + t->ops.release(t); else { kfree(t->priv); t->priv = NULL; @@ -207,13 +207,13 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(c); + microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(c); + tda8290_init(t); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c) == EINVAL) { + if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -222,7 +222,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(c) == EINVAL) { + if (tea5761_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -240,7 +240,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -248,13 +248,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_TDA9887: - tda9887_tuner_init(c); + tda9887_tuner_init(t); break; default: - default_tuner_init(c); + default_tuner_init(t); break; } @@ -426,9 +426,8 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) +static void tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); unsigned long freq, freq_fraction; const char *p; @@ -451,10 +450,10 @@ static void tuner_status(struct i2c_client *client) if (t->mode != V4L2_TUNER_RADIO) return; if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(client)); + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no"); + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); } } @@ -503,7 +502,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(&t->i2c) != EINVAL) { + if (tea5761_autodetection(t) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -520,7 +519,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(&t->i2c) == 0) { + if (tda8290_probe(t) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ @@ -531,7 +530,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(&t->i2c) != EINVAL) { + if (tea5767_autodetection(t) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -588,7 +587,7 @@ static int tuner_detach(struct i2c_client *client) } if (t->ops.release) - t->ops.release(client); + t->ops.release(t); else { kfree(t->priv); } @@ -613,7 +612,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); return EINVAL; } return 0; @@ -662,7 +661,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -722,9 +721,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (V4L2_TUNER_RADIO == t->mode) { if (t->ops.has_signal) - vt->signal = t->ops.has_signal(client); + vt->signal = t->ops.has_signal(t); if (t->ops.is_stereo) { - if (t->ops.is_stereo(client)) + if (t->ops.is_stereo(t)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -753,7 +752,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(client) + va->mode = t->ops.is_stereo(t) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } @@ -819,7 +818,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->type = t->mode; if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(client); + tuner->afc=t->ops.get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -830,12 +829,12 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* radio mode */ if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(client); + tuner->signal = t->ops.has_signal(t); tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(client) ? + tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } @@ -864,7 +863,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: if (t->ops.tuner_status) - t->ops.tuner_status(client); + t->ops.tuner_status(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 145045561a51..3cd1d446f2f3 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,18 +24,21 @@ #include #include +#include "tuner-i2c.h" extern unsigned const int tuner_count; +struct tuner; + struct tuner_operations { - void (*set_tv_freq)(struct i2c_client *c, unsigned int freq); - void (*set_radio_freq)(struct i2c_client *c, unsigned int freq); - int (*has_signal)(struct i2c_client *c); - int (*is_stereo)(struct i2c_client *c); - int (*get_afc)(struct i2c_client *c); - void (*tuner_status)(struct i2c_client *c); - void (*standby)(struct i2c_client *c); - void (*release)(struct i2c_client *c); + void (*set_tv_freq)(struct tuner *t, unsigned int freq); + void (*set_radio_freq)(struct tuner *t, unsigned int freq); + int (*has_signal)(struct tuner *t); + int (*is_stereo)(struct tuner *t); + int (*get_afc)(struct tuner *t); + void (*tuner_status)(struct tuner *t); + void (*standby)(struct tuner *t); + void (*release)(struct tuner *t); }; struct tuner { @@ -66,20 +69,20 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct i2c_client *c); +extern int default_tuner_init(struct tuner *t); -extern int tda9887_tuner_init(struct i2c_client *c); +extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct i2c_client *c); +extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct i2c_client *c); -extern int tda8290_probe(struct i2c_client *c); +extern int tda8290_init(struct tuner *t); +extern int tda8290_probe(struct tuner *t); -extern int tea5761_tuner_init(struct i2c_client *c); -extern int tea5761_autodetection(struct i2c_client *c); +extern int tea5761_tuner_init(struct tuner *t); +extern int tea5761_autodetection(struct tuner *t); -extern int tea5767_autodetection(struct i2c_client *c); -extern int tea5767_tuner_init(struct i2c_client *c); +extern int tea5767_autodetection(struct tuner *t); +extern int tea5767_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h new file mode 100644 index 000000000000..159019ec3373 --- /dev/null +++ b/drivers/media/video/tuner-i2c.h @@ -0,0 +1,70 @@ +/* + tuner-i2c.h - i2c interface for different tuners + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_I2C_H__ +#define __TUNER_I2C_H__ + +#include + +struct tuner_i2c_props { + u8 addr; + struct i2c_adapter *adap; +}; + +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = 0, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +#ifndef __TUNER_DRIVER_H__ +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + if ((debug)) \ + printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#endif /* __TUNER_DRIVER_H__ */ + +#endif /* __TUNER_I2C_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b98..eca2ff249a36 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -84,31 +84,32 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; + struct tuner_i2c_props i2c_props; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct i2c_client *c) +static int tuner_getstatus(struct tuner *t) { + struct tuner_simple_priv *priv = t->priv; unsigned char byte; - if (1 != i2c_master_recv(c,&byte,1)) + if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) return 0; return byte; } -static int tuner_signal(struct i2c_client *c) +static int tuner_signal(struct tuner *t) { - return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct i2c_client *c) +static int tuner_stereo(struct tuner *t) { int stereo, status; - struct tuner *t = i2c_get_clientdata(c); - status = tuner_getstatus (c); + status = tuner_getstatus(t); switch (t->type) { case TUNER_PHILIPS_FM1216ME_MK3: @@ -127,9 +128,8 @@ static int tuner_stereo(struct i2c_client *c) /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void default_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; @@ -285,13 +285,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x04; } /* set to the correct mode (analog or digital) */ - tuneraddr = c->addr; - c->addr = 0x0a; - if (2 != (rc = i2c_master_send(c,&buffer[0],2))) + tuneraddr = priv->i2c_props.addr; + priv->i2c_props.addr = 0x0a; + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - if (2 != (rc = i2c_master_send(c,&buffer[2],2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - c->addr = tuneraddr; + priv->i2c_props.addr = tuneraddr; /* FIXME: input */ break; } @@ -345,12 +345,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) } if (params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); switch (t->type) { @@ -362,7 +362,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x20; tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]); - if (2 != (rc = i2c_master_send(c,buffer,2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); break; case TUNER_MICROTUNE_4042FI5: @@ -375,7 +375,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) for (;;) { if (time_after(jiffies,timeout)) return; - if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; } @@ -393,17 +393,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); break; } } } -static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void default_set_radio_freq(struct tuner *t, unsigned int freq) { struct tunertype *tun; - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; @@ -498,16 +497,14 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config |= TDA9887_GAIN_NORMAL; if (params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } -static void tuner_release(struct i2c_client *c) +static void tuner_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -520,9 +517,8 @@ static struct tuner_operations simple_tuner_ops = { .release = tuner_release, }; -int default_tuner_init(struct i2c_client *c) +int default_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); @@ -530,9 +526,12 @@ int default_tuner_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); - strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); + strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); From e18f9444bda60a67e6feef00c354f8de0cdaeba7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:25:48 -0300 Subject: [PATCH 167/310] V4L/DVB (6128): hybrid tuner refactoring core changes, phase 1 Prepare tuner-core for conversion of tuner sub-drivers into dvb_frontend modules Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Oliver Endriss Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 9 ++ drivers/media/video/tuner-core.c | 131 ++++++++++++++++++---- drivers/media/video/tuner-driver.h | 3 + 3 files changed, 124 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f95de63d0e24..ffb83b0f68c3 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,6 +62,13 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_parameters { + unsigned int frequency; + unsigned int mode; + unsigned int audmode; + u64 std; +}; + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -72,6 +79,7 @@ struct dvb_tuner_ops { /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); @@ -80,6 +88,7 @@ struct dvb_tuner_ops { int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); #define TUNER_STATUS_LOCKED 1 +#define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); /** These are provided seperately from set_params in order to facilitate silicon diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 0363eae800e7..183bbb9ba6ab 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -70,6 +70,40 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ +static void fe_set_freq(struct tuner *t, unsigned int freq) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (NULL == fe_tuner_ops->set_analog_params) { + tuner_warn("Tuner frontend module has no way to set freq\n"); + return; + } + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); +} + +static void fe_release(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); +} + +static void fe_standby(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->sleep) + fe_tuner_ops->sleep(&t->fe); +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -171,6 +205,7 @@ static void set_type(struct i2c_client *c, unsigned int type, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -258,6 +293,17 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + } + + tuner_info("type set to %s\n", t->i2c.name); + if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -429,6 +475,7 @@ static int tuner_fixup_std(struct tuner *t) static void tuner_status(struct tuner *t) { unsigned long freq, freq_fraction; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; const char *p; switch (t->mode) { @@ -449,6 +496,15 @@ static void tuner_status(struct tuner *t) tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_LOCKED) + tuner_info("Tuner is locked.\n"); + if (tuner_status & TUNER_STATUS_STEREO) + tuner_info("Stereo: yes\n"); + } if (t->ops.has_signal) { tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } @@ -634,6 +690,7 @@ static inline int check_v4l2(struct tuner *t) static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -720,15 +777,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) - vt->flags |= - VIDEO_TUNER_STEREO_ON; - else - vt->flags &= - ~VIDEO_TUNER_STEREO_ON; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; + vt->signal = tuner_status & TUNER_STATUS_LOCKED + ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); } vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -751,9 +820,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + if (V4L2_TUNER_RADIO == t->mode) { + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + va->mode = (tuner_status & TUNER_STATUS_STEREO) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } return 0; } #endif @@ -804,6 +881,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); f->type = t->mode; + if (fe_tuner_ops->get_frequency) { + u32 abs_freq; + + fe_tuner_ops->get_frequency(&t->fe, &abs_freq); + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + (abs_freq * 2 + 125/2) / 125 : + (abs_freq + 62500/2) / 62500; + break; + } f->frequency = (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq; break; @@ -828,16 +914,23 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } /* radio mode */ - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } + if (fe_tuner_ops->get_status) { + u32 tuner_status; + fe_tuner_ops->get_status(&t->fe, &tuner_status); + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); + } tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 3cd1d446f2f3..d4c02b4abe71 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -25,6 +25,7 @@ #include #include #include "tuner-i2c.h" +#include "dvb_frontend.h" extern unsigned const int tuner_count; @@ -58,6 +59,8 @@ struct tuner { int using_v4l2; void *priv; + struct dvb_frontend fe; + /* used by tda9887 */ unsigned int tda9887_config; From 910bb3e3c5a5d8ed5028846728efc6a375d200eb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:22:20 -0300 Subject: [PATCH 168/310] V4L/DVB (6129): tda8290: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 367 +++++++++++++++++------------ drivers/media/video/tda8290.h | 35 +++ drivers/media/video/tuner-core.c | 16 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 270 insertions(+), 151 deletions(-) create mode 100644 drivers/media/video/tda8290.h diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index beb4a7e1d286..ec731d6fbfb8 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -16,12 +16,21 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This "tda8290" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tda8290.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda8290 " /* ---------------------------------------------------------------------- */ @@ -33,6 +42,11 @@ struct tda8290_priv { unsigned char tda827x_addr; unsigned char tda827x_ver; unsigned int sgIF; + + u32 frequency; + + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); }; /* ---------------------------------------------------------------------- */ @@ -81,19 +95,21 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827x_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; + unsigned int freq = params->frequency; - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827x_analog[i].lomax < N) { if(tda827x_analog[i + 1].lomax == 0) @@ -155,9 +171,9 @@ static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct tuner *t) +static void tda827x_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -204,57 +220,64 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct tuner *t, int high) +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char buf[] = {0x22, 0x01}; int arg; struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - if (t->config) { + + if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) + return; + + if (*priv->lna_cfg) { if (high) tuner_dbg("setting LNA to high gain\n"); else tuner_dbg("setting LNA to low gain\n"); } - switch (t->config) { + switch (*priv->lna_cfg) { case 0: /* no LNA */ break; case 1: /* switch is GPIO 0 of tda8290 */ case 2: /* turn Vsync on */ - if (t->std & V4L2_STD_MN) + if (params->std & V4L2_STD_MN) arg = 1; else arg = 0; - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; - if (t->config == 2) + if (*priv->lna_cfg == 2) buf[1] = high ? 1 : 0; i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[11]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; + unsigned int freq = params->frequency; - tda827xa_lna_gain(t, 1); + tda827xa_lna_gain(fe, 1, params); msleep(10); - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827xa_analog[i].lomax < N) { if(tda827xa_analog[i + 1].lomax == 0) @@ -302,7 +325,7 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain(t, 0); + tda827xa_lna_gain(fe, 0, params); msleep(100); tuner_reg[0] = 0x60; @@ -327,9 +350,9 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct tuner *t) +static void tda827xa_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -338,9 +361,9 @@ static void tda827xa_agcf(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct tuner *t, int close) +static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -358,9 +381,58 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; + char* mode; + + priv->tda827x_lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->tda8290_easy_mode = 0x01; + priv->tda827x_lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + priv->tda8290_easy_mode = 0x02; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x04; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x08; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x20; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + priv->tda8290_easy_mode = 0x40; + mode = "LC"; + } else { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + tuner_dbg("setting tda8290 to system %s\n", mode); +} + +static int tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->tuner_priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -383,7 +455,10 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) pll_stat; int i; - tuner_dbg("tda827xa config is 0x%02x\n", t->config); + set_audio(fe, params); + + if (priv->lna_cfg) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -399,11 +474,11 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(t, ifc, freq); + tda827xa_set_analog_params(fe, params); else - tda827x_tune(t, ifc, freq); + tda827x_set_analog_params(fe, params); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -433,9 +508,9 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(t); + tda827xa_agcf(fe); else - tda827x_agcf(t); + tda827x_agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -464,73 +539,20 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) } } - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); + + priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? + params->frequency * 125 / 2 : params->frequency * 62500; + return 0; } /*---------------------------------------------------------------------*/ -static void set_audio(struct tuner *t) +static int tda8290_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; - char* mode; - - priv->tda827x_lpsel = 0; - if (t->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; - mode = "MN"; - } else if (t->std & V4L2_STD_B) { - priv->sgIF = 108; - priv->tda8290_easy_mode = 0x02; - mode = "B"; - } else if (t->std & V4L2_STD_GH) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x04; - mode = "GH"; - } else if (t->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x08; - mode = "I"; - } else if (t->std & V4L2_STD_DK) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "DK"; - } else if (t->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x20; - mode = "L"; - } else if (t->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - priv->tda8290_easy_mode = 0x40; - mode = "LC"; - } else { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "xx"; - } - tuner_dbg("setting tda8290 to system %s\n", mode); -} - -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - struct tda8290_priv *priv = t->priv; - - set_audio(t); - tda8290_tune(t, priv->sgIF, freq); -} - -static void set_radio_freq(struct tuner *t, unsigned int freq) -{ - /* if frequency is 5.5 MHz */ - tda8290_tune(t, 88, freq); -} - -static int has_signal(struct tuner *t) -{ - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; @@ -540,44 +562,63 @@ static int has_signal(struct tuner *t) return (afc & 0x80)? 65535:0; } +static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda8290_priv *priv = fe->tuner_priv; + + int signal = tda8290_has_signal(fe); + *status = 0; + + /* for now, report based on afc status */ + if (signal) + *status = TUNER_STATUS_LOCKED; + + tuner_dbg("tda8290: AFC status: %d\n", signal); + + return 0; +} + /*---------------------------------------------------------------------*/ -static void standby(struct tuner *t) +static int tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); + + return 0; } -static void tda8290_init_if(struct tuner *t) +static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((t->config == 1) || (t->config == 2)) + if ((priv->lna_cfg) && + ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct tuner *t) +static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -587,28 +628,40 @@ static void tda8290_init_tuner(struct tuner *t) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct tuner *t) +static int tda8290_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tda8290_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = has_signal, - .standby = standby, - .release = tda8290_release, +static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda8290_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tda8290_tuner_ops = { + .sleep = tda8290_standby, + .set_analog_params = tda8290_set_params, + .release = tda8290_release, + .get_frequency = tda8290_get_frequency, + .get_status = tda8290_get_status, }; -int tda8290_init(struct tuner *t) +struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) { struct tda8290_priv *priv = NULL; u8 data; @@ -618,13 +671,17 @@ int tda8290_init(struct tuner *t) priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->lna_cfg = cfg->lna_cfg; + priv->tuner_callback = cfg->tuner_callback; + } - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -640,7 +697,7 @@ int tda8290_init(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -652,41 +709,52 @@ int tda8290_init(struct tuner *t) } if (tuner_addrs == 0) { tuner_addrs = 0x61; - tuner_info ("could not clearly identify tuner address, defaulting to %x\n", + tuner_info("could not clearly identify tuner address, defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; - tuner_info ("setting tuner address to %x\n", tuner_addrs); + tuner_info("setting tuner address to %x\n", tuner_addrs); } priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) - tuner_warn ("TDA827x access failed!\n"); + tuner_warn("TDA827x access failed!\n"); + + memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, + sizeof(struct dvb_tuner_ops)); + if ((data & 0x3c) == 0) { - strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 55000000; + fe->ops.tuner_ops.info.frequency_max = 860000000; + fe->ops.tuner_ops.info.frequency_step = 250000; priv->tda827x_ver = 0; } else { - strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 44000000; + fe->ops.tuner_ops.info.frequency_max = 906000000; + fe->ops.tuner_ops.info.frequency_step = 62500; priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", t->i2c.name); - - memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; - t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(t); - tda8290_init_if(t); - return 0; + tda8290_init_tuner(fe); + tda8290_init_if(fe); + return fe; } -int tda8290_probe(struct tuner *t) +int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct i2c_client *c = &t->i2c; + struct tuner_i2c_props i2c_props = { + .adap = i2c_adap, + .addr = i2c_addr + }; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; @@ -695,23 +763,30 @@ int tda8290_probe(struct tuner *t) unsigned char addr_dto_lsb = 0x07; unsigned char data; - i2c_master_send(c, easy_mode_b, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0) { - i2c_master_send(c, easy_mode_g, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0x7b) { return 0; } } - i2c_master_send(c, restore_9886, 3); + tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); return -1; } +EXPORT_SYMBOL_GPL(tda8290_probe); +EXPORT_SYMBOL_GPL(tda8290_attach); + +MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h new file mode 100644 index 000000000000..815ca1c78f80 --- /dev/null +++ b/drivers/media/video/tda8290.h @@ -0,0 +1,35 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA8290_H__ +#define __TDA8290_H__ + +#include +#include "dvb_frontend.h" + +struct tda8290_config +{ + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); +}; + +extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg); + +#endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 183bbb9ba6ab..f37fe83b1995 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "tda8290.h" #define UNSET (-1U) @@ -200,6 +201,15 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("====================== WARNING! ======================\n"); } +static void attach_tda8290(struct tuner *t) +{ + struct tda8290_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback + }; + tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -245,8 +255,10 @@ static void set_type(struct i2c_client *c, unsigned int type, microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(t); + { + attach_tda8290(t); break; + } case TUNER_TEA5767: if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; @@ -575,7 +587,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(t) == 0) { + if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index d4c02b4abe71..05d5f8575673 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -78,9 +78,6 @@ extern int tda9887_tuner_init(struct tuner *t); extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct tuner *t); -extern int tda8290_probe(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); From 96c0b7cfa5de1d6be0a6f6d202a6a078f5577d8f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:08 -0300 Subject: [PATCH 169/310] V4L/DVB (6130): mt20xx: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 246 ++++++++++++++++++++--------- drivers/media/video/mt20xx.h | 27 ++++ drivers/media/video/tuner-core.c | 3 +- drivers/media/video/tuner-driver.h | 2 - 4 files changed, 197 insertions(+), 81 deletions(-) create mode 100644 drivers/media/video/mt20xx.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 41bc91817a16..f49d1f4c40db 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,12 +1,20 @@ /* - * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. + * + * This "mt20xx" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "mt20xx.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "mt20xx " /* ---------------------------------------------------------------------- */ @@ -19,9 +27,6 @@ module_param(tv_antenna, int, 0644); static unsigned int radio_antenna = 0; module_param(radio_antenna, int, 0644); -/* from tuner-core.c */ -extern int tuner_debug; - /* ---------------------------------------------------------------------- */ #define MT2032 0x04 @@ -40,19 +45,31 @@ struct microtune_priv { struct tuner_i2c_props i2c_props; unsigned int xogc; - unsigned int radio_if2; + //unsigned int radio_if2; + + u32 frequency; }; -static void microtune_release(struct tuner *t) +static int microtune_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct microtune_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } // IsSpurInBand()? -static int mt2032_spurcheck(struct tuner *t, +static int mt2032_spurcheck(struct dvb_frontend *fe, int f1, int f2, int spectrum_from,int spectrum_to) { + struct microtune_priv *priv = fe->tuner_priv; int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -80,7 +97,7 @@ static int mt2032_spurcheck(struct tuner *t, return 1; } -static int mt2032_compute_freq(struct tuner *t, +static int mt2032_compute_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -89,6 +106,7 @@ static int mt2032_compute_freq(struct tuner *t, int *ret_sel, unsigned int xogc) //all in Hz { + struct microtune_priv *priv = fe->tuner_priv; unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -138,7 +156,7 @@ static int mt2032_compute_freq(struct tuner *t, return(-1); } - mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -162,9 +180,9 @@ static int mt2032_compute_freq(struct tuner *t, return 0; } -static int mt2032_check_lo_lock(struct tuner *t) +static int mt2032_check_lo_lock(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; int try,lock=0; unsigned char buf[2]; @@ -184,9 +202,9 @@ static int mt2032_check_lo_lock(struct tuner *t) return lock; } -static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) +static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int tad1; @@ -216,18 +234,18 @@ static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) buf[0]=0x0f; buf[1]=sel; tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); return lock; } -static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, +static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); @@ -237,7 +255,7 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; @@ -253,10 +271,10 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); if(optimize_vco) - lock=mt2032_optimize_vco(t,sel,lock); + lock=mt2032_optimize_vco(fe,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); @@ -279,12 +297,13 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, } -static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { int if2,from,to; // signal bandwidth and picture carrier - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC from = 40750*1000; to = 46750*1000; @@ -296,30 +315,64 @@ static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(fe, params->frequency*62500, 1090*1000*1000, if2, from, to); + + return 0; } -static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(t, freq * 1000 / 16, - 1085*1000*1000,if2,if2,if2); + mt2032_set_if_freq(fe, params->frequency * 125 / 2, + 1085*1000*1000,if2,if2,if2); + + return 0; } -static struct tuner_operations mt2032_tuner_ops = { - .set_tv_freq = mt2032_set_tv_freq, - .set_radio_freq = mt2032_set_radio_freq, - .release = microtune_release, +static int mt2032_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2032_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2032_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2032_tuner_ops = { + .set_analog_params = mt2032_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct tuner *t) +static int mt2032_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -368,14 +421,14 @@ static int mt2032_init(struct tuner *t) } while (xok != 1 ); priv->xogc=xogc; - memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); return(1); } -static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) +static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -385,9 +438,9 @@ static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -419,7 +472,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i div2a=(lo2/8)-1; div2b=lo2-(div2a+1)*8; - if (tuner_debug > 1) { + if (debug > 1) { tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", num1,num2,div1a,div1b,div2a,div2b); @@ -435,7 +488,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; - if (tuner_debug > 1) { + if (debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) @@ -448,43 +501,78 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned int if2; - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC if2 = 45750*1000; } else { // PAL if2 = 38900*1000; } - if (V4L2_TUNER_DIGITAL_TV == t->mode) { + if (V4L2_TUNER_DIGITAL_TV == params->mode) { // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(t, freq*62500, if2); - mt2050_set_antenna(t, tv_antenna); + mt2050_set_if_freq(fe, params->frequency*62500, if2); + mt2050_set_antenna(fe, tv_antenna); + + return 0; } -static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int if2; - mt2050_set_if_freq(t, freq * 1000 / 16, if2); - mt2050_set_antenna(t, radio_antenna); + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); + mt2050_set_antenna(fe, radio_antenna); + + return 0; } -static struct tuner_operations mt2050_tuner_ops = { - .set_tv_freq = mt2050_set_tv_freq, - .set_radio_freq = mt2050_set_radio_freq, - .release = microtune_release, +static int mt2050_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2050_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2050_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2050_tuner_ops = { + .set_analog_params = mt2050_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; -static int mt2050_init(struct tuner *t) +static int mt2050_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -502,12 +590,14 @@ static int mt2050_init(struct tuner *t) tuner_dbg("mt2050: sro is %x\n",buf[0]); - memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); return 0; } -int microtune_init(struct tuner *t) +struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct microtune_priv *priv = NULL; char *name; @@ -516,28 +606,21 @@ int microtune_init(struct tuner *t) priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); - if (t->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - priv->radio_if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - priv->radio_if2 = 33300 * 1000; - } name = "unknown"; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (tuner_debug) { + if (debug) { int i; tuner_dbg("MT20xx hexdump:"); for(i=0;i<21;i++) { @@ -556,10 +639,10 @@ int microtune_init(struct tuner *t) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(t); + mt2032_init(fe); break; case MT2050: - mt2050_init(t); + mt2050_init(fe); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -567,11 +650,18 @@ int microtune_init(struct tuner *t) return 0; } - strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, name, + sizeof(fe->ops.tuner_ops.info.name)); tuner_info("microtune %s found, OK\n",name); - return 0; + return fe; } +EXPORT_SYMBOL_GPL(microtune_attach); + +MODULE_DESCRIPTION("Microtune tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h new file mode 100644 index 000000000000..877dbef891ea --- /dev/null +++ b/drivers/media/video/mt20xx.h @@ -0,0 +1,27 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MT20XX_H__ +#define __MT20XX_H__ + +#include +#include "dvb_frontend.h" + +extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f37fe83b1995..f24ec1a18b45 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "mt20xx.h" #include "tda8290.h" #define UNSET (-1U) @@ -252,7 +253,7 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(t); + microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: { diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 05d5f8575673..87d937f2f740 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,8 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); From 7ab10bf72add23f0badf98ead92f58e34e14d35a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:40 -0300 Subject: [PATCH 170/310] V4L/DVB (6131): tea5761: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 132 +++++++++++++++++++---------- drivers/media/video/tea5761.h | 28 ++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 drivers/media/video/tea5761.h diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 9965ba48cffa..8cdaf474ffdd 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -11,15 +11,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5761.h" -#define PREFIX "TEA5761 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5761 " struct tea5761_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -118,11 +122,6 @@ struct tea5761_priv { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ static void tea5761_status_dump(unsigned char *buffer) { @@ -137,16 +136,18 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq counter %d\n", frq); + tuner_dbg("radio freq counter %d\n", frq); - if (t->mode == T_STANDBY) { + if (params->mode == T_STANDBY) { tuner_dbg("TEA5761 set to standby mode\n"); buffer[5] |= TEA5761_TNCTRL_MU; } else { @@ -154,10 +155,9 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) } - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5761 set to mono\n"); buffer[5] |= TEA5761_TNCTRL_MST; -; } else { tuner_dbg("TEA5761 set to stereo\n"); } @@ -166,18 +166,22 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) buffer[1] = (div >> 8) & 0x3f; buffer[2] = div & 0xff; - if (tuner_debug) + if (debug) tea5761_status_dump(buffer); if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5761_signal(struct tuner *t) +static int tea5761_signal(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -186,11 +190,11 @@ static int tea5761_signal(struct tuner *t) return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct tuner *t) +static int tea5761_stereo(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -203,58 +207,96 @@ static int tea5761_stereo(struct tuner *t) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct tuner *t) +static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5761_priv *priv = fe->tuner_priv; + int signal = tea5761_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5761: Signal strength: %d\n", signal); + + return 0; +} + +int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { unsigned char buffer[16]; int rc; - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { - tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); + printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { - tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); return EINVAL; } - tuner_warn("TEA5761 detected.\n"); + printk(KERN_WARNING "TEA5761 detected.\n"); return 0; } -static void tea5761_release(struct tuner *t) +static int tea5761_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tea5761_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5761_signal, - .is_stereo = tea5761_stereo, - .release = tea5761_release, +static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5761_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5761_tuner_ops = { + .info = { + .name = "tea5761", // Philips TEA5761HN FM Radio + }, + .set_analog_params = set_radio_freq, + .release = tea5761_release, + .get_frequency = tea5761_get_frequency, + .get_status = tea5761_get_status, }; -int tea5761_tuner_init(struct tuner *t) +struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(t) == EINVAL) - return EINVAL; + if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL) + return NULL; priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5761_attach); +EXPORT_SYMBOL_GPL(tea5761_autodetection); + +MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h new file mode 100644 index 000000000000..f287c0291bff --- /dev/null +++ b/drivers/media/video/tea5761.h @@ -0,0 +1,28 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5761_H__ +#define __TEA5761_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f24ec1a18b45..848ee6420c5c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -21,6 +21,7 @@ #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" +#include "tea5761.h" #define UNSET (-1U) @@ -270,7 +271,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(t) == EINVAL) { + if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -571,7 +572,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(t) != EINVAL) { + if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 87d937f2f740..bcb6a61c2086 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5761_tuner_init(struct tuner *t); -extern int tea5761_autodetection(struct tuner *t); - extern int tea5767_autodetection(struct tuner *t); extern int tea5767_tuner_init(struct tuner *t); From 8d0936ed15f509c32e8f81849be3a1cee80e2225 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:24:27 -0300 Subject: [PATCH 171/310] V4L/DVB (6132): tea5767: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 149 +++++++++++++++++++---------- drivers/media/video/tea5767.h | 29 ++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 drivers/media/video/tea5767.h diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 5a08ec2f99fb..cf908d853195 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -13,15 +13,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5767.h" -#define PREFIX "TEA5767 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5767 " struct tea5767_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -133,11 +137,6 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - static void tea5767_status_dump(unsigned char *buffer) { unsigned int div, frq; @@ -192,14 +191,16 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[5]; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); + tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); /* Rounds freq to next decimal value - for 62.5 KHz step */ /* frq = 20*(frq/16)+radio_frq[frq%16]; */ @@ -209,7 +210,7 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; buffer[4] = 0; - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; } else { @@ -219,26 +220,26 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) /* Should be replaced */ switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); buffer[3] |= TEA5767_XTAL_32768; /* const 700=4000*175 Khz - to adjust freq to right value */ div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; break; case TEA5767_HIGH_LO_32768: default: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[3] |= TEA5767_XTAL_32768; @@ -251,19 +252,23 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - if (tuner_debug) { + if (debug) { if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5767_signal(struct tuner *t) +static int tea5767_signal(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -272,11 +277,11 @@ static int tea5767_signal(struct tuner *t) return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct tuner *t) +static int tea5767_stereo(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -284,15 +289,31 @@ static int tea5767_stereo(struct tuner *t) rc = buffer[2] & TEA5767_STEREO_MASK; - tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + tuner_dbg("radio ST GET = %02x\n", rc); return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct tuner *t) +static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5767_priv *priv = fe->tuner_priv; + int signal = tea5767_signal(fe); + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5767: Signal strength: %d\n", signal); + + return 0; +} + +static int tea5767_standby(struct dvb_frontend *fe) { unsigned char buffer[5]; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -305,23 +326,25 @@ static void tea5767_standby(struct tuner *t) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return 0; } -int tea5767_autodetection(struct tuner *t) +int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { - tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); + if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { + printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } /* If all bytes are the same then it's a TV tuner and not a tea5767 */ if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - tuner_warn("All bytes are equal. It is not a TEA5767\n"); + printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); return EINVAL; } @@ -331,51 +354,73 @@ int tea5767_autodetection(struct tuner *t) * Byte 5: bit 7:0 : == 0 */ if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { - tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); + printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } /* It seems that tea5767 returns 0xff after the 5th byte */ if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { - tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n"); + printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n"); return EINVAL; } - tuner_warn("TEA5767 detected.\n"); + printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } -static void tea5767_release(struct tuner *t) +static int tea5767_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tea5767_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5767_signal, - .is_stereo = tea5767_stereo, - .standby = tea5767_standby, - .release = tea5767_release, +static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5767_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5767_tuner_ops = { + .info = { + .name = "tea5767", // Philips TEA5767HN FM Radio + }, + + .set_analog_params = set_radio_freq, + .sleep = tea5767_standby, + .release = tea5767_release, + .get_frequency = tea5767_get_frequency, + .get_status = tea5767_get_status, }; -int tea5767_tuner_init(struct tuner *t) +struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5767_priv *priv = NULL; priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5767_attach); +EXPORT_SYMBOL_GPL(tea5767_autodetection); + +MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h new file mode 100644 index 000000000000..68e9263badfd --- /dev/null +++ b/drivers/media/video/tea5767.h @@ -0,0 +1,29 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5767_H__ +#define __TEA5767_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 848ee6420c5c..9598a3da85f4 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -22,6 +22,7 @@ #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" +#include "tea5767.h" #define UNSET (-1U) @@ -262,7 +263,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (tea5767_tuner_init(t) == EINVAL) { + if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -600,7 +601,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(t) != EINVAL) { + if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index bcb6a61c2086..664f3467ee4f 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5767_autodetection(struct tuner *t); -extern int tea5767_tuner_init(struct tuner *t); - /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ From 4adad287de82703fd504fdab7aebe760196bb786 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:08 -0300 Subject: [PATCH 172/310] V4L/DVB (6133): tuner-simple: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 17 +- drivers/media/video/tuner-driver.h | 2 - drivers/media/video/tuner-simple.c | 294 ++++++++++++++++++----------- drivers/media/video/tuner-simple.h | 35 ++++ 4 files changed, 236 insertions(+), 112 deletions(-) create mode 100644 drivers/media/video/tuner-simple.h diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9598a3da85f4..8ee0be261076 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -17,12 +17,14 @@ #include #include #include +#include #include #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-simple.h" #define UNSET (-1U) @@ -213,6 +215,15 @@ static void attach_tda8290(struct tuner *t) tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); } +static void attach_simple_tuner(struct tuner *t) +{ + struct simple_tuner_config cfg = { + .type = t->type, + .tun = &tuners[t->type] + }; + simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -290,7 +301,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -298,13 +309,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_TDA9887: tda9887_tuner_init(t); break; default: - default_tuner_init(t); + attach_simple_tuner(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 664f3467ee4f..28a10da76d12 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -72,8 +72,6 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct tuner *t); - extern int tda9887_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index eca2ff249a36..2dbd91c8cb64 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,7 +1,8 @@ /* - * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. + * + * This "tuner-simple" module was split apart from the original "tuner" module. */ #include #include @@ -9,7 +10,14 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tuner-simple.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tuner-simple " static int offset = 0; module_param(offset, int, 0664); @@ -85,13 +93,18 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; struct tuner_i2c_props i2c_props; + + unsigned int type; + struct tunertype *tun; + + u32 frequency; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct tuner *t) +static int tuner_getstatus(struct dvb_frontend *fe) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) @@ -100,18 +113,20 @@ static int tuner_getstatus(struct tuner *t) return byte; } -static int tuner_signal(struct tuner *t) +static int tuner_signal(struct dvb_frontend *fe) { - return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct tuner *t) +static int tuner_stereo(struct dvb_frontend *fe) { + struct tuner_simple_priv *priv = fe->tuner_priv; + int stereo, status; - status = tuner_getstatus(t); + status = tuner_getstatus(fe); - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: @@ -126,20 +141,38 @@ static int tuner_stereo(struct tuner *t) } +static int simple_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tuner_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + + return 0; +} + /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct tuner *t, unsigned int freq) +static int simple_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; u8 buffer[4]; int rc, IFPCoff, i, j; enum param_type desired_type; - struct tuner_params *params; + struct tuner_params *t_params; - tun = &tuners[t->type]; + tun = priv->tun; /* IFPCoff = Video Intermediate Frequency - Vif: 940 =16*58.75 NTSC/J (Japan) @@ -153,14 +186,14 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) 171.2=16*10.70 FM Radio (at set_radio_freq) */ - if (t->std == V4L2_STD_NTSC_M_JP) { + if (params->std == V4L2_STD_NTSC_M_JP) { IFPCoff = 940; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if ((t->std & V4L2_STD_MN) && - !(t->std & ~V4L2_STD_MN)) { + } else if ((params->std & V4L2_STD_MN) && + !(params->std & ~V4L2_STD_MN)) { IFPCoff = 732; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if (t->std == V4L2_STD_SECAM_LC) { + } else if (params->std == V4L2_STD_SECAM_LC) { IFPCoff = 543; desired_type = TUNER_PARAM_TYPE_SECAM; } else { @@ -173,49 +206,49 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) continue; break; } - /* use default tuner_params if desired_type not available */ + /* use default tuner_t_params if desired_type not available */ if (desired_type != tun->params[j].type) { - tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n", - IFPCoff,t->type); + tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n", + IFPCoff, priv->type); j = 0; } - params = &tun->params[j]; + t_params = &tun->params[j]; - for (i = 0; i < params->count; i++) { - if (freq > params->ranges[i].limit) + for (i = 0; i < t_params->count; i++) { + if (params->frequency > t_params->ranges[i].limit) continue; break; } - if (i == params->count) { + if (i == t_params->count) { tuner_dbg("TV frequency out of range (%d > %d)", - freq, params->ranges[i - 1].limit); - freq = params->ranges[--i].limit; + params->frequency, t_params->ranges[i - 1].limit); + params->frequency = t_params->ranges[--i].limit; } - config = params->ranges[i].config; - cb = params->ranges[i].cb; + config = t_params->ranges[i].config; + cb = t_params->ranges[i].cb; /* i == 0 -> VHF_LO * i == 1 -> VHF_HI * i == 2 -> UHF */ tuner_dbg("tv: param %d, range %d\n",j,i); - div=freq + IFPCoff + offset; + div=params->frequency + IFPCoff + offset; tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", - freq / 16, freq % 16 * 100 / 16, + params->frequency / 16, params->frequency % 16 * 100 / 16, IFPCoff / 16, IFPCoff % 16 * 100 / 16, offset / 16, offset % 16 * 100 / 16, div); /* tv norm specific stuff for multi-norm tuners */ - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_SECAM: // FI1216MF /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ cb &= ~0x03; - if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM + if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM cb |= PHILIPS_MF_SET_STD_L; - else if (t->std & V4L2_STD_SECAM_LC) + else if (params->std & V4L2_STD_SECAM_LC) cb |= PHILIPS_MF_SET_STD_LC; else /* V4L2_STD_B|V4L2_STD_GH */ cb |= PHILIPS_MF_SET_STD_BG; @@ -224,16 +257,16 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_TEMIC_4046FM5: cb &= ~0x0f; - if (t->std & V4L2_STD_PAL_BG) { + if (params->std & V4L2_STD_PAL_BG) { cb |= TEMIC_SET_PAL_BG; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= TEMIC_SET_PAL_I; - } else if (t->std & V4L2_STD_PAL_DK) { + } else if (params->std & V4L2_STD_PAL_DK) { cb |= TEMIC_SET_PAL_DK; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= TEMIC_SET_PAL_L; } @@ -242,13 +275,13 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_PHILIPS_FQ1216ME: cb &= ~0x0f; - if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { cb |= PHILIPS_SET_PAL_BGDK; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= PHILIPS_SET_PAL_I; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= PHILIPS_SET_PAL_L; } @@ -260,7 +293,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* 0x02 -> NTSC antenna input 1 */ /* 0x03 -> NTSC antenna input 2 */ cb &= ~0x03; - if (!(t->std & V4L2_STD_ATSC)) + if (!(params->std & V4L2_STD_ATSC)) cb |= 2; /* FIXME: input */ break; @@ -280,7 +313,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[2] = 0x17; buffer[3] = 0x00; cb &= ~0x40; - if (t->std & V4L2_STD_ATSC) { + if (params->std & V4L2_STD_ATSC) { cb |= 0x40; buffer[1] = 0x04; } @@ -296,7 +329,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -308,42 +341,42 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[3] = cb; } priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && - !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && + !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); - if (t->std == V4L2_STD_SECAM_LC) { - if (params->port1_active ^ params->port1_invert_for_secam_lc) + if (params->std == V4L2_STD_SECAM_LC) { + if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active ^ params->port2_invert_for_secam_lc) + if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) config |= TDA9887_PORT2_ACTIVE; } else { - if (params->port1_active) + if (t_params->port1_active) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active) + if (t_params->port2_active) config |= TDA9887_PORT2_ACTIVE; } - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; if (is_secam_l) { - if (i == 0 && params->default_top_secam_low) - config |= TDA9887_TOP(params->default_top_secam_low); - else if (i == 1 && params->default_top_secam_mid) - config |= TDA9887_TOP(params->default_top_secam_mid); - else if (params->default_top_secam_high) - config |= TDA9887_TOP(params->default_top_secam_high); + if (i == 0 && t_params->default_top_secam_low) + config |= TDA9887_TOP(t_params->default_top_secam_low); + else if (i == 1 && t_params->default_top_secam_mid) + config |= TDA9887_TOP(t_params->default_top_secam_mid); + else if (t_params->default_top_secam_high) + config |= TDA9887_TOP(t_params->default_top_secam_high); } else { - if (i == 0 && params->default_top_low) - config |= TDA9887_TOP(params->default_top_low); - else if (i == 1 && params->default_top_mid) - config |= TDA9887_TOP(params->default_top_mid); - else if (params->default_top_high) - config |= TDA9887_TOP(params->default_top_high); + if (i == 0 && t_params->default_top_low) + config |= TDA9887_TOP(t_params->default_top_low); + else if (i == 1 && t_params->default_top_mid) + config |= TDA9887_TOP(t_params->default_top_mid); + else if (t_params->default_top_high) + config |= TDA9887_TOP(t_params->default_top_high); } - if (params->default_pll_gating_18) + if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } @@ -353,7 +386,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); - switch (t->type) { + switch (priv->type) { case TUNER_LG_TDVS_H06XF: /* Set the Auxiliary Byte. */ buffer[0] = buffer[2]; @@ -374,7 +407,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* Wait until the PLL locks */ for (;;) { if (time_after(jiffies,timeout)) - return; + return 0; if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; @@ -398,27 +431,30 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } } + return 0; } -static void default_set_radio_freq(struct tuner *t, unsigned int freq) +static int simple_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tunertype *tun; - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 buffer[4]; u16 div; int rc, j; - struct tuner_params *params; + struct tuner_params *t_params; + unsigned int freq = params->frequency; - tun = &tuners[t->type]; + tun = priv->tun; for (j = tun->count-1; j > 0; j--) if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) break; - /* default params (j=0) will be used if desired type wasn't found */ - params = &tun->params[j]; + /* default t_params (j=0) will be used if desired type wasn't found */ + t_params = &tun->params[j]; /* Select Radio 1st IF used */ - switch (params->radio_if) { + switch (t_params->radio_if) { case 0: /* 10.7 MHz */ freq += (unsigned int)(10.7*16000); break; @@ -429,16 +465,16 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq += (unsigned int)(41.3*16000); break; default: - tuner_warn("Unsupported radio_if value %d\n", params->radio_if); - return; + tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if); + return 0; } /* Bandswitch byte */ - switch (t->type) { + switch (priv->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); - return; + tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); + return 0; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: @@ -461,7 +497,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) break; } - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps @@ -469,7 +505,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -483,61 +519,105 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) buffer[0],buffer[1],buffer[2],buffer[3]); priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - if (params->port1_active && !params->port1_fm_high_sensitivity) + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active && !params->port2_fm_high_sensitivity) + if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) config |= TDA9887_PORT2_ACTIVE; - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; -/* if (params->port1_set_for_fm_mono) +/* if (t_params->port1_set_for_fm_mono) config &= ~TDA9887_PORT1_ACTIVE;*/ - if (params->fm_gain_normal) + if (t_params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; - if (params->radio_if == 2) + if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + + return 0; } -static void tuner_release(struct tuner *t) +static int simple_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - kfree(t->priv); - t->priv = NULL; + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = simple_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = simple_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; } -static struct tuner_operations simple_tuner_ops = { - .set_tv_freq = default_set_tv_freq, - .set_radio_freq = default_set_radio_freq, - .has_signal = tuner_signal, - .is_stereo = tuner_stereo, - .release = tuner_release, + +static int simple_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops simple_tuner_ops = { + .set_analog_params = simple_set_params, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, }; -int default_tuner_init(struct tuner *t) +struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) { struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->type = cfg->type; + priv->tun = cfg->tun; - tuner_info("type set to %d (%s)\n", - t->type, tuners[t->type].name); - strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name); - return 0; + strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name)); + + return fe; } + +EXPORT_SYMBOL_GPL(simple_tuner_attach); + +MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h new file mode 100644 index 000000000000..75cd45b7145d --- /dev/null +++ b/drivers/media/video/tuner-simple.h @@ -0,0 +1,35 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_SIMPLE_H__ +#define __TUNER_SIMPLE_H__ + +#include +#include "dvb_frontend.h" + +struct simple_tuner_config +{ + /* chip type */ + unsigned int type; + struct tunertype *tun; +}; + +extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg); + +#endif /* __TUNER_SIMPLE_H__ */ From ca805d57cf5ea7482ed3da28653f30621249ee45 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:35 -0300 Subject: [PATCH 173/310] V4L/DVB (6134): tuner: alter build to produce separate modules Break tuner.ko into separate modules. This was a quick change - Tuner sub-drivers are still static-linked to tuner.ko, this will change after using dvb_attach and removing the probing functions. After this change, one can deselect undesired tuner sub-drivers via Kconfig. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 56 ++++++++++++++++++++++++++++++ drivers/media/video/Kconfig | 9 ----- drivers/media/video/Makefile | 12 ++++--- drivers/media/video/mt20xx.h | 10 ++++++ drivers/media/video/tda8290.h | 19 ++++++++++ drivers/media/video/tea5761.h | 19 ++++++++++ drivers/media/video/tea5767.h | 18 ++++++++++ drivers/media/video/tuner-simple.h | 11 ++++++ 8 files changed, 141 insertions(+), 13 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index d9d033e07e19..3f8cfa873de5 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,6 +69,62 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + +menuconfig VIDEO_TUNER_CUSTOMIZE + bool "Customize analog tuner modules to build" + depends on VIDEO_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if VIDEO_TUNER_CUSTOMIZE + +config TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config TUNER_TDA8290 + tristate "TDA 8290+8275(a) tuner combo" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +endif # VIDEO_TUNER_CUSTOMIZE config VIDEO_BUF depends on PCI diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 0e1d2ccc4e81..04756c342cba 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,15 +505,6 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. -config TUNER_TEA5761 - bool "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on I2C - select VIDEO_TUNER - help - Say Y here to include support for Philips TEA5761 radio tuner. - If in doubt, say N. - config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 113e525f6dab..00699c36ec1a 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,10 +4,7 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ - mt20xx.o tda8290.o tea5767.o tda9887.o - -tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o +tuner-objs := tuner-core.o tuner-types.o tda9887.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -83,6 +80,13 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o + +obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o +obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_TUNER_TEA5761) += tea5761.o + obj-$(CONFIG_VIDEO_BUF) += video-buf.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h index 877dbef891ea..5e9c825d2e91 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/video/mt20xx.h @@ -20,8 +20,18 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 815ca1c78f80..107b24b05aa1 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -26,10 +26,29 @@ struct tda8290_config int (*tuner_callback) (void *dev, int command,int arg); }; +#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr, struct tda8290_config *cfg); +#else +static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h index f287c0291bff..73a03b427843 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/video/tea5761.h @@ -20,9 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 68e9263badfd..5d78281adcc2 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,10 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h index 75cd45b7145d..9089939a8c02 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/video/tuner-simple.h @@ -27,9 +27,20 @@ struct simple_tuner_config struct tunertype *tun; }; +#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct simple_tuner_config *cfg); +#else +static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TUNER_SIMPLE_H__ */ From 8fb3b9f7a9e0420150bf6cb8a3c20f45d372cce4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 30 Aug 2007 23:00:43 -0300 Subject: [PATCH 174/310] V4L/DVB (6136): dvb_frontend: add get_rf_strength function pointer to dvb_tuner_ops Add get_rf_strength function pointer to dvb_tuner_ops, so that rf signal strength can be read directly from the tuner driver by the dvb demodulator driver and / or the analog tuning system. This is an internal api addition -- userspace is not affected. Signed-off-by: Michael Krufky Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index ffb83b0f68c3..a5262e852c82 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -90,6 +90,7 @@ struct dvb_tuner_ops { #define TUNER_STATUS_LOCKED 1 #define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); + int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); /** These are provided seperately from set_params in order to facilitate silicon * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ From 735f0b9af1748602bb7f3a8009c31cf5f133eec8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:39 -0300 Subject: [PATCH 175/310] V4L/DVB (6137): tuner-simple: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 58 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2dbd91c8cb64..7b93d3b1f4c6 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -102,7 +102,7 @@ struct tuner_simple_priv { /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct dvb_frontend *fe) +static int tuner_read_status(struct dvb_frontend *fe) { struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; @@ -113,47 +113,60 @@ static int tuner_getstatus(struct dvb_frontend *fe) return byte; } -static int tuner_signal(struct dvb_frontend *fe) +static inline int tuner_signal(const int status) { - return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; + return (status & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct dvb_frontend *fe) +static inline int tuner_stereo(const int type, const int status) { - struct tuner_simple_priv *priv = fe->tuner_priv; - - int stereo, status; - - status = tuner_getstatus(fe); - - switch (priv->type) { + switch (type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: case TUNER_LG_NTSC_TAPE: - stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); - break; + return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); default: - stereo = status & TUNER_STEREO; + return status & TUNER_STEREO; } +} - return stereo; +static inline int tuner_islocked(const int status) +{ + return (status & TUNER_FL); +} + +static inline int tuner_afcstatus(const int status) +{ + return (status & TUNER_AFC) - 2; } static int simple_get_status(struct dvb_frontend *fe, u32 *status) { struct tuner_simple_priv *priv = fe->tuner_priv; - int signal = tuner_signal(fe); + int tuner_status = tuner_read_status(fe); *status = 0; - if (signal) + if (tuner_islocked(tuner_status)) *status = TUNER_STATUS_LOCKED; - if (tuner_stereo(fe)) + if (tuner_stereo(priv->type, tuner_status)) *status |= TUNER_STATUS_STEREO; - tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); + + return 0; +} + +static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(tuner_read_status(fe)); + + *strength = signal; + + tuner_dbg("Signal strength: %d\n", signal); return 0; } @@ -580,9 +593,10 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) static struct dvb_tuner_ops simple_tuner_ops = { .set_analog_params = simple_set_params, - .release = simple_release, - .get_frequency = simple_get_frequency, - .get_status = simple_get_status, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, + .get_rf_strength = simple_get_rf_strength, }; struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, From fd443f7444180c1cd9cbcb816ebf65c8b8e35301 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:57 -0300 Subject: [PATCH 176/310] V4L/DVB (6138): tea5761: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 64 ++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 8cdaf474ffdd..2150222a3860 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -177,49 +177,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5761_signal(struct dvb_frontend *fe) +static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + memset(buffer, 0, 16); + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { + tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); + return -EREMOTEIO; + } - return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + return 0; } -static int tea5761_stereo(struct dvb_frontend *fe) +static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); - rc = buffer[9] & TEA5761_TUNCHECK_STEREO; + tuner_dbg("Signal strength: %d\n", signal); - tuner_dbg("TEA5761 radio ST GET = %02x\n", rc); + return signal; +} - return (rc ? V4L2_TUNER_SUB_STEREO : 0); +static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5761_priv *priv = fe->tuner_priv; - int signal = tea5761_signal(fe); + unsigned char buffer[16]; *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5761_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5761_read_status(fe, buffer)) { + if (tea5761_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } - tuner_dbg("tea5761: Signal strength: %d\n", signal); + return 0; +} + +static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[16]; + + *strength = 0; + + if (0 == tea5761_read_status(fe, buffer)) + *strength = tea5761_signal(fe, buffer); return 0; } @@ -266,6 +283,7 @@ static struct dvb_tuner_ops tea5761_tuner_ops = { .release = tea5761_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, + .get_rf_strength = tea5761_get_rf_strength, }; struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, From 6b897f2c3982af51134ba83f4b6de71d28d35944 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:40:14 -0300 Subject: [PATCH 177/310] V4L/DVB (6139): tea5767: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 63 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index cf908d853195..71df419df7bc 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -264,48 +264,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5767_signal(struct dvb_frontend *fe) +static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) + memset(buffer, 0, 5); + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + return -EREMOTEIO; + } - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + return 0; } -static int tea5767_stereo(struct dvb_frontend *fe) +static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); - rc = buffer[2] & TEA5767_STEREO_MASK; + tuner_dbg("Signal strength: %d\n", signal); - tuner_dbg("radio ST GET = %02x\n", rc); + return signal; +} - return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); +static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int stereo = buffer[2] & TEA5767_STEREO_MASK; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5767_priv *priv = fe->tuner_priv; - int signal = tea5767_signal(fe); + unsigned char buffer[5]; + *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5767_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5767_read_status(fe, buffer)) { + if (tea5767_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } - tuner_dbg("tea5767: Signal strength: %d\n", signal); + return 0; +} + +static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[5]; + + *strength = 0; + + if (0 == tea5767_read_status(fe, buffer)) + *strength = tea5767_signal(fe, buffer); return 0; } @@ -393,6 +411,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { .release = tea5767_release, .get_frequency = tea5767_get_frequency, .get_status = tea5767_get_status, + .get_rf_strength = tea5767_get_rf_strength, }; struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, From 3782e050f8860fb701d4cb14df16cd4ed9cce2d2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:53:00 -0300 Subject: [PATCH 178/310] V4L/DVB (6140): tda8290: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index ec731d6fbfb8..0e5cf459d3ed 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -553,27 +553,35 @@ static int tda8290_set_params(struct dvb_frontend *fe, static int tda8290_has_signal(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->tuner_priv; + int ret; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; + /* for now, report based on afc status */ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - return (afc & 0x80)? 65535:0; + + ret = (afc & 0x80) ? 65535 : 0; + + tuner_dbg("AFC status: %d\n", ret); + + return ret; } static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) { - struct tda8290_priv *priv = fe->tuner_priv; - - int signal = tda8290_has_signal(fe); *status = 0; - /* for now, report based on afc status */ - if (signal) + if (tda8290_has_signal(fe)) *status = TUNER_STATUS_LOCKED; - tuner_dbg("tda8290: AFC status: %d\n", signal); + return 0; +} + +static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + *strength = tda8290_has_signal(fe); return 0; } @@ -656,6 +664,7 @@ static struct dvb_tuner_ops tda8290_tuner_ops = { .release = tda8290_release, .get_frequency = tda8290_get_frequency, .get_status = tda8290_get_status, + .get_rf_strength = tda8290_get_rf_strength, }; struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, From 1f5ef19779df2c2f75870332b37dd3004c08a515 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:38:02 -0300 Subject: [PATCH 179/310] V4L/DVB (6141): tuner: use get_rf_strength instead of get_status to determine signal strength Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 8ee0be261076..2f74379f4e4b 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -110,6 +110,17 @@ static void fe_standby(struct tuner *t) fe_tuner_ops->sleep(&t->fe); } +static int fe_has_signal(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + u16 strength; + + if (fe_tuner_ops->get_rf_strength) + fe_tuner_ops->get_rf_strength(&t->fe, &strength); + + return strength; +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -326,6 +337,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->ops.set_radio_freq = fe_set_freq; t->ops.standby = fe_standby; t->ops.release = fe_release; + t->ops.has_signal = fe_has_signal; } tuner_info("type set to %s\n", t->i2c.name); @@ -807,12 +819,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - if (tuner_status & TUNER_STATUS_STEREO) - vt->flags |= VIDEO_TUNER_STEREO_ON; - else - vt->flags &= ~VIDEO_TUNER_STEREO_ON; - vt->signal = tuner_status & TUNER_STATUS_LOCKED - ? 65535 : 0; + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { if (t->ops.is_stereo) { if (t->ops.is_stereo(t)) @@ -822,9 +832,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->flags &= ~VIDEO_TUNER_STEREO_ON; } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ vt->rangelow = radio_range[0] * 16000; @@ -948,15 +959,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; } else { if (t->ops.is_stereo) { tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; From f61b48f7a838bb3d089b12fc9d03fd53c9ef5022 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 1 Sep 2007 02:02:51 -0300 Subject: [PATCH 180/310] V4L/DVB (6142): cx25840: fix build warning Fix the following build warning: CC [M] cx25840-core.o cx25840-core.c: In function 'init_dll1': cx25840-core.c:147: warning: implicit declaration of function 'udelay' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 90f7859bb48e..15f191e170d2 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include From 275511a0aca8483c03df1c6e3a33a27cee334709 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: [PATCH 181/310] V4L/DVB (6149): Add I2C_HW_B_CX23885 for Conexant 23885/23887 PCIe bridge Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 4891e03ad23a..a271b67a8e2d 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -197,6 +197,7 @@ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */ #define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */ +#define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */ From d19770e5178a4bc49641711246360c25781d20a4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: [PATCH 182/310] V4L/DVB (6150): Add CX23885/CX23887 PCIe bridge driver This is a new framework to support boards based on the CX23885/7 PCIe bridge. The framework supports digital (no analog yet) Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 1 + drivers/media/video/cx23885/Kconfig | 17 + drivers/media/video/cx23885/Makefile | 9 + drivers/media/video/cx23885/cx23885-cards.c | 198 +++ drivers/media/video/cx23885/cx23885-core.c | 1601 +++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 199 +++ drivers/media/video/cx23885/cx23885-i2c.c | 375 +++++ drivers/media/video/cx23885/cx23885-reg.h | 429 +++++ drivers/media/video/cx23885/cx23885.h | 295 ++++ 9 files changed, 3124 insertions(+) create mode 100644 drivers/media/video/cx23885/Kconfig create mode 100644 drivers/media/video/cx23885/Makefile create mode 100644 drivers/media/video/cx23885/cx23885-cards.c create mode 100644 drivers/media/video/cx23885/cx23885-core.c create mode 100644 drivers/media/video/cx23885/cx23885-dvb.c create mode 100644 drivers/media/video/cx23885/cx23885-i2c.c create mode 100644 drivers/media/video/cx23885/cx23885-reg.h create mode 100644 drivers/media/video/cx23885/cx23885.h diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 00699c36ec1a..9e99d2e1c1bd 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -124,5 +124,6 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o +obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig new file mode 100644 index 000000000000..ea53466dacbe --- /dev/null +++ b/drivers/media/video/cx23885/Kconfig @@ -0,0 +1,17 @@ +config VIDEO_CX23885 + tristate "Conexant cx23885 (2388x successor) support" + depends on VIDEO_DEV && PCI && I2C + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_BTCX + select VIDEO_BUF + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_IR + ---help--- + This is a video4linux driver for Conexant 23885 based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx23885 + diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile new file mode 100644 index 000000000000..665067022d2a --- /dev/null +++ b/drivers/media/video/cx23885/Makefile @@ -0,0 +1,9 @@ +cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o + +obj-$(CONFIG_VIDEO_CX23885) += cx23885.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c new file mode 100644 index 000000000000..9344fb5d95f6 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -0,0 +1,198 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "cx23885.h" + +/* ------------------------------------------------------------------ */ +/* board config info */ + +struct cx23885_board cx23885_boards[] = { + [CX23885_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .bridge = CX23885_BRIDGE_UNDEFINED, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 0, + },{ + .type = CX23885_VMUX_COMPOSITE2, + .vmux = 1, + },{ + .type = CX23885_VMUX_COMPOSITE3, + .vmux = 2, + },{ + .type = CX23885_VMUX_COMPOSITE4, + .vmux = 3, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { + .name = "Hauppauge WinTV-HVR1800lp", + .bridge = CX23885_BRIDGE_885, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800] = { + .name = "Hauppauge WinTV-HVR1800", + .bridge = CX23885_BRIDGE_887, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, +}; +const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); + +/* ------------------------------------------------------------------ */ +/* PCI subsystem IDs */ + +struct cx23885_subid cx23885_subids[] = { + { + .subvendor = 0x0070, + .subdevice = 0x3400, + .card = CX23885_BOARD_UNKNOWN, + },{ + .subvendor = 0x0070, + .subdevice = 0x7600, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, + },{ + .subvendor = 0x0070, + .subdevice = 0x7800, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7801, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, +}; +const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); + +void cx23885_card_list(struct cx23885_dev *dev) +{ + int i; + + if (0 == dev->pci->subsystem_vendor && + 0 == dev->pci->subsystem_device) { + printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n" + "%s: be autodetected. Please pass card= insmod option to\n" + "%s: workaround that. Redirect complaints to the vendor of\n" + "%s: the TV card. Best regards,\n" + "%s: -- tux\n", + dev->name, dev->name, dev->name, dev->name, dev->name); + } else { + printk("%s: Your board isn't known (yet) to the driver. You can\n" + "%s: try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + dev->name, dev->name, dev->name, dev->name); + } + printk("%s: Here is a list of valid choices for the card= insmod option:\n", + dev->name); + for (i = 0; i < cx23885_bcount; i++) + printk("%s: card=%d -> %s\n", + dev->name, i, cx23885_boards[i].name); +} + +static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); + + + /* Make sure we support the board model */ + switch (tv.model) + { + case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + break; + default: + printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +void cx23885_card_setup(struct cx23885_dev *dev) +{ + static u8 eeprom[256]; + + if (dev->i2c_bus[0].i2c_rc == 0) { + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + } + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if (dev->i2c_bus[0].i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0x80); + break; + } +} + +/* ------------------------------------------------------------------ */ + +EXPORT_SYMBOL(cx23885_boards); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c new file mode 100644 index 000000000000..876d396fb7a3 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -0,0 +1,1601 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" + +MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card,"card type"); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) + +static unsigned int cx23885_devcount; + +static DEFINE_MUTEX(devlist); +static LIST_HEAD(cx23885_devlist); + +#define NO_SYNC_LINE (-1U) + +/* + * CX23885 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23885_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x10000, + .ctrl_start = 0x10500, + .cdt = 0x10900, + .fifo_start = 0x3000, + .fifo_size = 0x1000, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + .jumponly = 1, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +/* FIXME, these allocations will change when + * analog arrives. The be reviewed. + * CX23887 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23887_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +static int cx23885_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ RISC_SYNC >> 28 ] = "sync", + [ RISC_WRITE >> 28 ] = "write", + [ RISC_WRITEC >> 28 ] = "writec", + [ RISC_READ >> 28 ] = "read", + [ RISC_READC >> 28 ] = "readc", + [ RISC_JUMP >> 28 ] = "jump", + [ RISC_SKIP >> 28 ] = "skip", + [ RISC_WRITERM >> 28 ] = "writerm", + [ RISC_WRITECM >> 28 ] = "writecm", + [ RISC_WRITECR >> 28 ] = "writecr", + }; + static int incr[16] = { + [ RISC_WRITE >> 28 ] = 3, // 2 + [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_SKIP >> 28 ] = 1, + [ RISC_SYNC >> 28 ] = 1, + [ RISC_WRITERM >> 28 ] = 3, + [ RISC_WRITECM >> 28 ] = 3, + [ RISC_WRITECR >> 28 ] = 4, + }; + static char *bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + do_gettimeofday(&buf->vb.ts); + dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + count, buf->count); + buf->vb.state = STATE_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); +} +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); + +int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i,lines; + u32 cdt; + + if (ch->cmds_start == 0) + { + dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } else { + dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + if (lines > 6) + lines = 6; + BUG_ON(lines < 2); + + cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8+4, cpu_to_le32(8) ); + cx_write(8+8, cpu_to_le32(0) ); + + /* write CDT */ + for (i = 0; i < lines; i++) { + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i + 4, 0); + cx_write(cdt + 16*i + 8, 0); + cx_write(cdt + 16*i + 12, 0); + } + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines*16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) ); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines*16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) -1); + + dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", + cx23885_boards[dev->board].bridge, + ch->name, + bpl, + lines); + + return 0; +} + +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) +{ + static char *name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + u32 risc; + unsigned int i,j,n; + + printk("%s: %s - dma channel status dump\n", + dev->name, ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + printk("%s: cmds: %-15s: 0x%08x\n", + dev->name, name[i], + cx_read(ch->cmds_start + 4*i)); + + for (i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 4 * (i+14)); + printk("%s: risc%d: ", dev->name, i); + cx23885_risc_decode(risc); + } + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ + printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + n = cx23885_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i+j)); + printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc, j); + } + } + + printk("%s: fifo: 0x%08x -> 0x%x\n", + dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + printk("%s: ctrl: 0x%08x -> 0x%x\n", + dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + printk("%s: ptr1_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr1_reg)); + printk("%s: ptr2_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr2_reg)); + printk("%s: cnt1_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt1_reg)); + printk("%s: cnt2_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt2_reg)); +} + +void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +{ + struct cx23885_dev *dev = port->dev; + unsigned int i,j,n; + + printk("%s: risc disasm: %p [dma=0x%08lx]\n", + dev->name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk("%s: %04d: ", dev->name, i); + n = cx23885_risc_decode(risc->cpu[i]); + for (j = 1; j < n; j++) + printk("%s: %04d: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc->cpu[i+j], j); + if (risc->cpu[i] == RISC_JUMP) + break; + } +} + +void cx23885_shutdown(struct cx23885_dev *dev) +{ + /* disable RISC controller */ + cx_write(DEV_CNTRL2, 0); + + /* Disable all IR activity */ + cx_write(IR_CNTRL_REG, 0); + + /* Disable Video A/B activity */ + cx_write(VID_A_DMA_CTL, 0); + cx_write(VID_B_DMA_CTL, 0); + cx_write(VID_C_DMA_CTL, 0); + + /* Disable Audio activity */ + cx_write(AUD_INT_DMA_CTL, 0); + cx_write(AUD_EXT_DMA_CTL, 0); + + /* Disable Serial port */ + cx_write(UART_CTL, 0); + + /* Disable Interrupts */ + cx_write(PCI_INT_MSK, 0); + cx_write(VID_A_INT_MSK, 0); + cx_write(VID_B_INT_MSK, 0); + cx_write(VID_C_INT_MSK, 0); + cx_write(AUDIO_INT_INT_MSK, 0); + cx_write(AUDIO_EXT_INT_MSK, 0); + +} + +void cx23885_reset(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + cx23885_shutdown(dev); + + cx_write(PCI_INT_STAT, 0xffffffff); + cx_write(VID_A_INT_STAT, 0xffffffff); + cx_write(VID_B_INT_STAT, 0xffffffff); + cx_write(VID_C_INT_STAT, 0xffffffff); + cx_write(AUDIO_INT_INT_STAT, 0xffffffff); + cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); + cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + + mdelay(100); + +#if SRAM + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); + +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + + +static int cx23885_pci_quirks(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + cx_clear(RDR_TLCTL0, 1 << 4); + break; + } + return 0; +} + +static int get_resources(struct cx23885_dev *dev) +{ + if (request_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0), + dev->name)) + return 0; + + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci,0)); + + return -EBUSY; +} + +static void cx23885_timeout(unsigned long data); +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +static int cx23885_ir_init(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + break; + } + + return 0; +} + +static int cx23885_dev_setup(struct cx23885_dev *dev) +{ + int i; + + mutex_init(&dev->lock); + + atomic_inc(&dev->refcount); + + dev->nr = cx23885_devcount++; + dev->pci_bus = dev->pci->bus->number; + dev->pci_slot = PCI_SLOT(dev->pci->devfn); + dev->pci_irqmask = 0x001f00; + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].reg_stat = I2C1_STAT; + dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; + dev->i2c_bus[0].reg_addr = I2C1_ADDR; + dev->i2c_bus[0].reg_rdata = I2C1_RDATA; + dev->i2c_bus[0].reg_wdata = I2C1_WDATA; + dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ + + /* External Master 2 Bus */ + dev->i2c_bus[1].nr = 1; + dev->i2c_bus[1].dev = dev; + dev->i2c_bus[1].reg_stat = I2C2_STAT; + dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; + dev->i2c_bus[1].reg_addr = I2C2_ADDR; + dev->i2c_bus[1].reg_rdata = I2C2_RDATA; + dev->i2c_bus[1].reg_wdata = I2C2_WDATA; + dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ + + /* Internal Master 3 Bus */ + dev->i2c_bus[2].nr = 2; + dev->i2c_bus[2].dev = dev; + dev->i2c_bus[2].reg_stat = I2C3_STAT; + dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; + dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_rdata = I2C3_RDATA; + dev->i2c_bus[2].reg_wdata = I2C3_WDATA; + dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ + + /* Transport bus init dma queue */ + spin_lock_init(&dev->ts2.slock); + dev->ts2.dev = dev; + dev->ts2.nr = 2; + dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); + INIT_LIST_HEAD(&dev->ts2.mpegq.queued); + dev->ts2.mpegq.timeout.function = cx23885_timeout; + dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; + init_timer(&dev->ts2.mpegq.timeout); + + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + sprintf(dev->name,"cx23885[%d]", dev->nr); + + if (get_resources(dev) < 0) { + printk(KERN_ERR "CORE %s No more PCIe resources for " + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); + + cx23885_devcount--; + goto fail_free; + } + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* PCIe stuff */ + dev->lmmio = ioremap(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + dev->bmmio = (u8 __iomem *)dev->lmmio; + + cx23885_pci_quirks(dev); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); + + /* Configure the hardware internal memory for fifos */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_UNDEFINED: + case CX23885_BRIDGE_885: + dev->sram_channels = cx23885_sram_channels; + break; + case CX23885_BRIDGE_887: + dev->sram_channels = cx23887_sram_channels; + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + /* init hardware */ + cx23885_reset(dev); + + cx23885_i2c_register(&dev->i2c_bus[0]); + cx23885_i2c_register(&dev->i2c_bus[1]); + cx23885_i2c_register(&dev->i2c_bus[2]); + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + cx23885_card_setup(dev); + cx23885_ir_init(dev); + + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + } + + return 0; + +fail_free: + kfree(dev); + return -ENODEV; +} + +void cx23885_dev_unregister(struct cx23885_dev *dev) +{ + release_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + if (!atomic_dec_and_test(&dev->refcount)) + return; + + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); + cx23885_i2c_unregister(&dev->i2c_bus[1]); + cx23885_i2c_unregister(&dev->i2c_bus[0]); + + iounmap(dev->lmmio); +} + +static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) +{ + struct scatterlist *sg; + unsigned int line,todo; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset+=bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines) +{ + u32 instructions,fields; + u32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions += 2; + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines); + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) +{ + u32 instructions; + u32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + /* Jump and write need an extra dword */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + u32 *rp; + int rc; + + if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + return 0; +} + +void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +{ + BUG_ON(in_interrupt()); + videobuf_waiton(&buf->vb,0,0); + videobuf_dma_unmap(q, &buf->vb.dma); + videobuf_dma_free(&buf->vb.dma); + btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); + buf->vb.state = STATE_NEEDS_INIT; +} + +static int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, + buf->vb.width, buf->vb.height, buf->vb.field); + +#if SRAM + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, + &cx23885_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, + &cx23887_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + if(debug > 5) + cx23885_risc_disasm(port, &buf->risc); + + /* write TS length to chip */ + cx_write(port->reg_lngth, buf->vb.width); + + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, + cx23885_boards[dev->board].portc ); + return -EINVAL; + } + + // FIXME: review the need for these two lines + dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); + udelay(100); + + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); + cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); + + // FIXME: review the need for this + cx_write(GPIO2, 0x00); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + cx_write(port->reg_vld_misc, 0x00); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + break; + default: + // FIXME + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); + udelay(100); + + /* reset counter to zero */ + cx_write(port->reg_gpcnt_ctl, 3); + q->count = 1; + + /* A bug in the current 887 implementation, causes an NMI assert during + * starting or stopping interrupts or dma. Avoid the bug for the time being, + * enabling the developer to work on the demod/tuner locking work. + */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + /* enable irqs */ + dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); + cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_set(port->reg_dma_ctl, port->dma_ctl_val); + cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); + break; + case CX23885_BRIDGE_887: + // FIXME + dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); + break; + default: + // FIXME: generate a sensible switch-default message + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + dprintk(1, "%s() Register Dump\n", __FUNCTION__); + dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); + dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); + dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); + dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); + dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); + dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); + dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); + dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); + + cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + + dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); + dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); + dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); + dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); + dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); + dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); + dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); + dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); + dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); + return 0; +} + +static int cx23885_stop_dma(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + /* Stop interrupts and DMA */ + cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + + return 0; +} + +static int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + struct list_head *item; + + dprintk(5, "%s()\n", __FUNCTION__); + if (list_empty(&q->active)) + { + struct cx23885_buffer *prev; + prev = NULL; + + dprintk(5, "%s() queue is empty\n", __FUNCTION__); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } + return 0; + } + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_dma(port, q, buf); + list_for_each(item,&q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field) +{ + struct cx23885_dev *dev = port->dev; + int size = port->ts_packet_size * port->ts_packet_count; + int rc; + + dprintk(1, "%s: %p\n", __FUNCTION__, buf); + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = port->ts_packet_size; + buf->vb.height = port->ts_packet_count; + buf->vb.size = size; + buf->vb.field = field /*V4L2_FIELD_TOP*/; + + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + cx23885_risc_databuffer(dev->pci, &buf->risc, + buf->vb.dma.sglist, + buf->vb.width, buf->vb.height); + } + buf->vb.state = STATE_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q,buf); + return rc; +} + +void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) +{ + struct cx23885_buffer *prev; + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *cx88q = &port->mpegq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&cx88q->active)) { + dprintk( 1, "queue is empty - first active\n" ); + list_add_tail(&buf->vb.queue,&cx88q->active); + cx23885_start_dma(port, cx88q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] %s - first active\n", + buf, buf->vb.i, __FUNCTION__); + + } else { + dprintk( 1, "queue is not empty - append to active\n" ); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); + list_add_tail(&buf->vb.queue,&cx88q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk( 1, "[%p/%d] %s - append to active\n", + buf, buf->vb.i, __FUNCTION__); + } +} + +/* ----------------------------------------------------------- */ + +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + struct cx23885_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&port->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = STATE_ERROR; + wake_up(&buf->vb.done); + dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); + } + if (restart) + { + dprintk(1, "restarting queue\n" ); + cx23885_restart_queue(port, q); + } + spin_unlock_irqrestore(&port->slock,flags); +} + +void cx23885_cancel_buffers(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + + dprintk(1, "%s()\n", __FUNCTION__ ); + del_timer_sync(&q->timeout); + cx23885_stop_dma(port); + do_cancel_buffers(port, "cancel", 0); +} + +static void cx23885_timeout(unsigned long data) +{ + struct cx23885_tsport *port = (struct cx23885_tsport *)data; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s()\n",__FUNCTION__); + + if (debug > 5) +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + { + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); + } +#endif + cx23885_stop_dma(port); + do_cancel_buffers(port, "timeout", 1); +} + +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) + +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 + +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 + +static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cx23885_dev *dev = dev_id; + struct cx23885_tsport *port = &dev->ts2; + u32 pci_status, pci_mask; + u32 ts2_status, ts2_mask; + int count = 0, handled = 0; + + pci_status = cx_read(PCI_INT_STAT); + pci_mask = cx_read(PCI_INT_MSK); + + ts2_status = cx_read(VID_C_INT_STAT); + ts2_mask = cx_read(VID_C_INT_MSK); + + if ( (pci_status == 0) && (ts2_status == 0) ) + goto out; + + count = cx_read(port->reg_gpcnt); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + + if ( (pci_status & PCI_MSK_RISC_RD) || + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) + { + + if (pci_status & PCI_MSK_RISC_RD) + dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD); + if (pci_status & PCI_MSK_RISC_WR) + dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR); + if (pci_status & PCI_MSK_AL_RD) + dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD); + if (pci_status & PCI_MSK_AL_WR) + dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR); + if (pci_status & PCI_MSK_APB_DMA) + dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA); + if (pci_status & PCI_MSK_VID_C) + dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C); + if (pci_status & PCI_MSK_VID_B) + dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B); + if (pci_status & PCI_MSK_VID_A) + dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A); + if (pci_status & PCI_MSK_AUD_INT) + dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT); + if (pci_status & PCI_MSK_AUD_EXT) + dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT); + + } + + if ( (ts2_status & VID_C_MSK_OPC_ERR) || + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) + { + if (ts2_status & VID_C_MSK_OPC_ERR) + dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); + if (ts2_status & VID_C_MSK_BAD_PKT) + dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); + if (ts2_status & VID_C_MSK_SYNC) + dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); + if (ts2_status & VID_C_MSK_OF) + dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); +#endif + + + } else if (ts2_status & VID_C_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts2_status & VID_C_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + + cx_write(VID_C_INT_STAT, ts2_status); + cx_write(PCI_INT_STAT, pci_status); + handled = 1; +out: + return IRQ_RETVAL(handled); +} + +static int __devinit cx23885_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx23885_dev *dev; + int err; + + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail_free; + } + + if (cx23885_dev_setup(dev) < 0) { + err = -EINVAL; + goto fail_free; + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0)); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail_irq; + } + + err = request_irq(pci_dev->irq, cx23885_irq + , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail_irq; + } + + pci_set_drvdata(pci_dev, dev); + return 0; + +fail_irq: + cx23885_dev_unregister(dev); +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx23885_finidev(struct pci_dev *pci_dev) +{ + struct cx23885_dev *dev = pci_get_drvdata(pci_dev); + + cx23885_shutdown(dev); + + pci_disable_device(pci_dev); + + /* unregister stuff */ + free_irq(pci_dev->irq, dev); + pci_set_drvdata(pci_dev, NULL); + + mutex_lock(&devlist); + list_del(&dev->devlist); + mutex_unlock(&devlist); + + cx23885_dev_unregister(dev); + kfree(dev); +} + +static struct pci_device_id cx23885_pci_tbl[] = { + { + /* CX23885 */ + .vendor = 0x14f1, + .device = 0x8852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* CX23887 Rev 2 */ + .vendor = 0x14f1, + .device = 0x8880, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); + +static struct pci_driver cx23885_pci_driver = { + .name = "cx23885", + .id_table = cx23885_pci_tbl, + .probe = cx23885_initdev, + .remove = __devexit_p(cx23885_finidev), + /* TODO */ + .suspend = NULL, + .resume = NULL, +}; + +static int cx23885_init(void) +{ + printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx23885_pci_driver); +} + +static void cx23885_fini(void) +{ + pci_unregister_driver(&cx23885_pci_driver); +} + +module_init(cx23885_init); +module_exit(cx23885_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c new file mode 100644 index 000000000000..4ff85f75f9f7 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -0,0 +1,199 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "dvb-pll.h" +#include + +#include "s5h1409.h" +#include "mt2131.h" + +static unsigned int debug = 2; + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int dvb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx23885_tsport *port = q->priv_data; + + port->ts_packet_size = 188 * 4; + port->ts_packet_count = 32; + + *size = port->ts_packet_size * port->ts_packet_count; + *count = 32; + return 0; +} + +static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_tsport *port = q->priv_data; + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); +} + +static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_tsport *port = q->priv_data; + cx23885_buf_queue(port, (struct cx23885_buffer*)vb); +} + +static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + cx23885_free_buffer(q, (struct cx23885_buffer*)vb); +} + +static struct videobuf_queue_ops dvb_qops = { + .buf_setup = dvb_buf_setup, + .buf_prepare = dvb_buf_prepare, + .buf_queue = dvb_buf_queue, + .buf_release = dvb_buf_release, +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + +static struct s5h1409_config hauppauge_hvr1800_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + + +static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { + 0x61 +}; + +static struct mt2131_config hauppauge_hvr1800_tunerconfig = { + 0x61 +}; + +static int dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + /* init struct videobuf_dvb */ + port->dvb.name = dev->name; + + /* init frontend */ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, + 0); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, + 0); + } + break; + default: + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + dev->name); + break; + } + if (NULL == port->dvb.frontend) { + printk("%s: frontend initialization failed\n", dev->name); + return -1; + } + + /* Put the analog decoder in standby to keep it quiet */ + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + /* register everything */ + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); +} + +int cx23885_dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + int err; + + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dev->board, + dev->name, + dev->pci_bus, + dev->pci_slot); + + err = -ENODEV; + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) + goto fail_core; + + /* dvb stuff */ + printk("%s: cx23885 based dvb card\n", dev->name); + videobuf_queue_init( + &port->dvb.dvbq, + &dvb_qops, + dev->pci, + &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), + port); + err = dvb_register(port); + if (err != 0) + printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); + + fail_core: + return err; +} + +int cx23885_dvb_unregister(struct cx23885_tsport *port) +{ + /* dvb */ + if(port->dvb.frontend) + videobuf_dvb_unregister(&port->dvb); + + return 0; +} diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c new file mode 100644 index 000000000000..6f5e207c11a6 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -0,0 +1,375 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx23885.h" + +#include + +static unsigned int i2c_debug = 2; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); + +static unsigned int i2c_scan = 0; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 64 + +#define I2C_EXTEND (1 << 3) +#define I2C_NOSTOP (1 << 4) + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 wdata, addr, ctrl; + int retval, cnt; + + dprintk(1, "%s()\n", __FUNCTION__); + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + + /* dev, reg + first byte */ + addr = (msg->addr << 25) | msg->buf[0]; + wdata = msg->buf[0]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (msg->len > 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + wdata = msg->buf[cnt]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 ctrl, cnt; + int retval; + + dprintk(1, "%s()\n", __FUNCTION__); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + for(cnt = 0; cnt < msg->len; cnt++) { + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; + if (i2c_debug) { + if (!(ctrl & I2C_NOSTOP)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + int i, retval = 0; + + dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); + + for (i = 0 ; i < num; i++) { + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" + , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static int attach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, client->name); + + if (!client->driver->command) + return 0; + + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "i2c detach [client=%s]\n", client->name); + + return 0; +} + +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +{ +// struct cx23885_dev *dev = bus->dev; + + if (bus->i2c_rc != 0) + return; + + i2c_clients_command(&bus->i2c_adap, cmd, arg); +} + +static int cx23885_algo_control(struct i2c_adapter *adap, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 cx23885_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm cx23885_i2c_algo_template = { + .master_xfer = i2c_xfer, + .algo_control = cx23885_algo_control, + .functionality = cx23885_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter cx23885_i2c_adap_template = { + .name = "cx23885", + .owner = THIS_MODULE, + .id = I2C_HW_B_CX23885, + .algo = &cx23885_i2c_algo_template, +// .class = I2C_CLASS_TV_ANALOG, + .client_register = attach_inform, + .client_unregister = detach_inform, +}; + +static struct i2c_client cx23885_i2c_client_template = { + .name = "cx23885 internal", +}; + +static char *i2c_devs[128] = { + [ 0x32 >> 1 ] = "cx24227", + [ 0x88 >> 1 ] = "cx25837", + [ 0x84 >> 1 ] = "tda8295", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "mt2131/tda8275", + [ 0xc2 >> 1 ] = "mt2131/tda8275", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int cx23885_i2c_register(struct cx23885_i2c *bus) +{ + struct cx23885_dev *dev = bus->dev; + + dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); + + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + + bus->i2c_adap.dev.parent = &dev->pci->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; + bus->i2c_adap.algo_data = bus; + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + if (0 == bus->i2c_rc) { + printk("%s: i2c bus %d registered\n", dev->name, bus->nr); + if (i2c_scan) + do_i2c_scan(dev->name, &bus->i2c_client); + } else + printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + + return bus->i2c_rc; +} + +int cx23885_i2c_unregister(struct cx23885_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +EXPORT_SYMBOL(cx23885_call_i2c_clients); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h new file mode 100644 index 000000000000..5cb692f20d28 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -0,0 +1,429 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX23885_REG_H_ +#define _CX23885_REG_H_ + + +/* +Address Map +0x00000000 -> 0x00009000 TX SRAM (Fifos) +0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT + +EACH CMDS struct is 0x80 bytes long + +DMAx_PTR1 = 0x03040 address of first cluster +DMAx_PTR2 = 0x10600 address of the CDT +DMAx_CNT1 = cluster size in (bytes >> 4) -1 +DMAx_CNT2 = total cdt size for all entries >> 3 + +Cluster Descriptor entry = 4 DWORDS + DWORD 0 -> ptr to cluster + DWORD 1 Reserved + DWORD 2 Reserved + DWORD 3 Reserved + +Channel manager Data Structure entry = 20 DWORD + 0 IntialProgramCounterLow + 1 IntialProgramCounterHigh + 2 ClusterDescriptorTableBase + 3 ClusterDescriptorTableSize + 4 InstructionQueueBase + 5 InstructionQueueSize +... Reserved + 19 Reserved + + +*/ + +/* Risc Instructions */ +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_IRQ1 0x01000000 +#define RISC_IRQ2 0x02000000 +#define RISC_EOL 0x04000000 +#define RISC_SOL 0x08000000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_SYNC 0x80000000 +#define RISC_RESYNC 0x80008000 +#define RISC_READ 0x90000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 + +//#define RISC_SYNC_ODD 0x80000000 +//#define RISC_SYNC_EVEN 0x80000200 +//#define RISC_RESYNC_ODD 0x80008000 +//#define RISC_RESYNC_EVEN 0x80008200 + +// Do we need these? +#define RISC_WRITEC 0x50000000 +#define RISC_READC 0xA0000000 + +// Is this used? +#define RISC_IMM 0x00000001 + +//#define RISC_CNT_NONE 0x00000000 +//#define RISC_CNT_RSVR 0x00020000 +//#define RISC_JMP_SRP 0x01 + +/* Audio and Video Core */ +#define HOST_REG1 0x00000000 +#define HOST_REG2 0x00000001 +#define HOST_REG3 0x00000002 + +/* Chip Configuration Registers */ +#define CHIP_CTRL 0x00000100 +#define AFE_CTRL 0x00000104 +#define VID_PLL_INT_POST 0x00000108 +#define VID_PLL_FRAC 0x0000010C +#define AUX_PLL_INT_POST 0x00000110 +#define AUX_PLL_FRAC 0x00000114 +#define SYS_PLL_INT_POST 0x00000118 +#define SYS_PLL_FRAC 0x0000011C +#define PIN_CTRL 0x00000120 +#define AUD_IO_CTRL 0x00000124 +#define AUD_LOCK1 0x00000128 +#define AUD_LOCK2 0x0000012C +#define POWER_CTRL 0x00000130 +#define AFE_DIAG_CTRL1 0x00000134 +#define AFE_DIAG_CTRL3 0x0000013C +#define PLL_DIAG_CTRL 0x00000140 +#define AFE_CLK_OUT_CTRL 0x00000144 +#define DLL1_DIAG_CTRL 0x0000015C + +/* GPIO[23:19] Output Enable */ +#define GPIO2_OUT_EN_REG 0x00000160 +/* GPIO[23:19] Data Registers */ +#define GPIO2 0x00000164 + +#define IFADC_CTRL 0x00000180 + +/* Infrared Remote Registers */ +#define IR_CNTRL_REG 0x00000200 +#define IR_TXCLK_REG 0x00000204 +#define IR_RXCLK_REG 0x00000208 +#define IR_CDUTY_REG 0x0000020C +#define IR_STAT_REG 0x00000210 +#define IR_IRQEN_REG 0x00000214 +#define IR_FILTR_REG 0x00000218 +#define IR_FIFO_REG 0x0000023C + +/* Video Decoder Registers */ +#define MODE_CTRL 0x00000400 +#define OUT_CTRL1 0x00000404 +#define OUT_CTRL2 0x00000408 +#define GEN_STAT 0x0000040C +#define INT_STAT_MASK 0x00000410 +#define LUMA_CTRL 0x00000414 +#define HSCALE_CTRL 0x00000418 +#define VSCALE_CTRL 0x0000041C +#define CHROMA_CTRL 0x00000420 +#define VBI_LINE_CTRL1 0x00000424 +#define VBI_LINE_CTRL2 0x00000428 +#define VBI_LINE_CTRL3 0x0000042C +#define VBI_LINE_CTRL4 0x00000430 +#define VBI_LINE_CTRL5 0x00000434 +#define VBI_FC_CFG 0x00000438 +#define VBI_MISC_CFG1 0x0000043C +#define VBI_MISC_CFG2 0x00000440 +#define VBI_PAY1 0x00000444 +#define VBI_PAY2 0x00000448 +#define VBI_CUST1_CFG1 0x0000044C +#define VBI_CUST1_CFG2 0x00000450 +#define VBI_CUST1_CFG3 0x00000454 +#define VBI_CUST2_CFG1 0x00000458 +#define VBI_CUST2_CFG2 0x0000045C +#define VBI_CUST2_CFG3 0x00000460 +#define VBI_CUST3_CFG1 0x00000464 +#define VBI_CUST3_CFG2 0x00000468 +#define VBI_CUST3_CFG3 0x0000046C +#define HORIZ_TIM_CTRL 0x00000470 +#define VERT_TIM_CTRL 0x00000474 +#define SRC_COMB_CFG 0x00000478 +#define CHROMA_VBIOFF_CFG 0x0000047C +#define FIELD_COUNT 0x00000480 +#define MISC_TIM_CTRL 0x00000484 +#define DFE_CTRL1 0x00000488 +#define DFE_CTRL2 0x0000048C +#define DFE_CTRL3 0x00000490 +#define PLL_CTRL 0x00000494 +#define HTL_CTRL 0x00000498 +#define COMB_CTRL 0x0000049C +#define CRUSH_CTRL 0x000004A0 +#define SOFT_RST_CTRL 0x000004A4 +#define CX885_VERSION 0x000004B4 +#define VBI_PASS_CTRL 0x000004BC + +/* Audio Decoder Registers */ +/* 8051 Configuration */ +#define DL_CTL 0x00000800 +#define STD_DET_STATUS 0x00000804 +#define STD_DET_CTL 0x00000808 +#define DW8051_INT 0x0000080C +#define GENERAL_CTL 0x00000810 +#define AAGC_CTL 0x00000814 +#define DEMATRIX_CTL 0x000008CC +#define PATH1_CTL1 0x000008D0 +#define PATH1_VOL_CTL 0x000008D4 +#define PATH1_EQ_CTL 0x000008D8 +#define PATH1_SC_CTL 0x000008DC +#define PATH2_CTL1 0x000008E0 +#define PATH2_VOL_CTL 0x000008E4 +#define PATH2_EQ_CTL 0x000008E8 +#define PATH2_SC_CTL 0x000008EC + +/* Sample Rate Converter */ +#define SRC_CTL 0x000008F0 +#define SRC_LF_COEF 0x000008F4 +#define SRC1_CTL 0x000008F8 +#define SRC2_CTL 0x000008FC +#define SRC3_CTL 0x00000900 +#define SRC4_CTL 0x00000904 +#define SRC5_CTL 0x00000908 +#define SRC6_CTL 0x0000090C +#define BAND_OUT_SEL 0x00000910 +#define I2S_N_CTL 0x00000914 +#define I2S_OUT_CTL 0x00000918 +#define AUTOCONFIG_REG 0x000009C4 + +/* Audio ADC Registers */ +#define DSM_CTRL1 0x00000000 +#define DSM_CTRL2 0x00000001 +#define CHP_EN_CTRL 0x00000002 +#define CHP_CLK_CTRL1 0x00000004 +#define CHP_CLK_CTRL2 0x00000005 +#define BG_REF_CTRL 0x00000006 +#define SD2_SW_CTRL1 0x00000008 +#define SD2_SW_CTRL2 0x00000009 +#define SD2_BIAS_CTRL 0x0000000A +#define AMP_BIAS_CTRL 0x0000000C +#define CH_PWR_CTRL1 0x0000000E +#define CH_PWR_CTRL2 0x0000000F +#define DSM_STATUS1 0x00000010 +#define DSM_STATUS2 0x00000011 +#define DIG_CTL1 0x00000012 +#define DIG_CTL2 0x00000013 +#define I2S_TX_CFG 0x0000001A + +#define DEV_CNTRL2 0x00040000 +#define PCI_INT_MSK 0x00040010 +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 +#define PCI_INT_STAT 0x00040014 +#define PCI_INT_MSTAT 0x00040018 + +#define VID_A_INT_MSK 0x00040020 +#define VID_A_INT_STAT 0x00040024 +#define VID_A_INT_MSTAT 0x00040028 +#define VID_A_INT_SSTAT 0x0004002C + +#define VID_B_INT_MSK 0x00040030 +#define VID_B_INT_STAT 0x00040034 +#define VID_B_INT_MSTAT 0x00040038 +#define VID_B_INT_SSTAT 0x0004003C + +#define VID_C_INT_MSK 0x00040040 +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 +#define VID_C_INT_STAT 0x00040044 +#define VID_C_INT_MSTAT 0x00040048 +#define VID_C_INT_SSTAT 0x0004004C + +#define AUDIO_INT_INT_MSK 0x00040050 +#define AUDIO_INT_INT_STAT 0x00040054 +#define AUDIO_INT_INT_MSTAT 0x00040058 +#define AUDIO_INT_INT_SSTAT 0x0004005C + +#define AUDIO_EXT_INT_MSK 0x00040060 +#define AUDIO_EXT_INT_STAT 0x00040064 +#define AUDIO_EXT_INT_MSTAT 0x00040068 +#define AUDIO_EXT_INT_SSTAT 0x0004006C + +#define RDR_CFG0 0x00050000 +#define RDR_CFG1 0x00050004 +#define RDR_TLCTL0 0x00050318 + +/* APB DMAC Current Buffer Pointer */ +#define DMA1_PTR1 0x00100000 +#define DMA2_PTR1 0x00100004 +#define DMA3_PTR1 0x00100008 +#define DMA4_PTR1 0x0010000C +#define DMA5_PTR1 0x00100010 +#define DMA6_PTR1 0x00100014 +#define DMA7_PTR1 0x00100018 +#define DMA8_PTR1 0x0010001C + +/* APB DMAC Current Table Pointer */ +#define DMA1_PTR2 0x00100040 +#define DMA2_PTR2 0x00100044 +#define DMA3_PTR2 0x00100048 +#define DMA4_PTR2 0x0010004C +#define DMA5_PTR2 0x00100050 +#define DMA6_PTR2 0x00100054 +#define DMA7_PTR2 0x00100058 +#define DMA8_PTR2 0x0010005C + +/* APB DMAC Buffer Limit */ +#define DMA1_CNT1 0x00100080 +#define DMA2_CNT1 0x00100084 +#define DMA3_CNT1 0x00100088 +#define DMA4_CNT1 0x0010008C +#define DMA5_CNT1 0x00100090 +#define DMA6_CNT1 0x00100094 +#define DMA7_CNT1 0x00100098 +#define DMA8_CNT1 0x0010009C + +/* APB DMAC Table Size */ +#define DMA1_CNT2 0x001000C0 +#define DMA2_CNT2 0x001000C4 +#define DMA3_CNT2 0x001000C8 +#define DMA4_CNT2 0x001000CC +#define DMA5_CNT2 0x001000D0 +#define DMA6_CNT2 0x001000D4 +#define DMA7_CNT2 0x001000D8 +#define DMA8_CNT2 0x001000DC + +/* Timer Counters */ +#define TM_CNT_LDW 0x00110000 +#define TM_CNT_UW 0x00110004 +#define TM_LMT_LDW 0x00110008 +#define TM_LMT_UW 0x0011000C + +/* GPIO */ +#define GP0_IO 0x00110010 +#define GPIO_ISM 0x00110014 +#define SOFT_RESET 0x0011001C + +/* GPIO (417 Microsoftcontroller) RW Data */ +#define MC417_RWD 0x00110020 + +/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ +#define MC417_OEN 0x00110024 +#define MC417_CTL 0x00110028 +#define CLK_DELAY 0x00110048 +#define PAD_CTRL 0x0011004C + +/* Video A Interface */ +#define VID_A_GPCNT 0x00130020 +#define VBI_A_GPCNT 0x00130024 +#define VID_A_GPCNT_CTL 0x00130030 +#define VBI_A_GPCNT_CTL 0x00130034 +#define VID_A_DMA_CTL 0x00130040 +#define VID_A_VIP_CTRL 0x00130080 +#define VID_A_PIXEL_FRMT 0x00130084 +#define VID_A_VBI_CTRL 0x00130088 + +/* Video B Interface */ +#define VID_B_DMA 0x00130100 +#define VBI_B_DMA 0x00130108 +#define VID_B_GPCNT 0x00130120 +#define VBI_B_GPCNT 0x00130124 +#define VID_B_GPCNT_CTL 0x00130130 +#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_DMA_CTL 0x00130140 +#define VID_B_SRC_SEL 0x00130144 +#define VID_B_LNGTH 0x00130150 +#define VID_B_HW_SOP_CTL 0x00130154 +#define VID_B_GEN_CTL 0x00130158 +#define VID_B_BD_PKT_STATUS 0x0013015C +#define VID_B_SOP_STATUS 0x00130160 +#define VID_B_FIFO_OVFL_STAT 0x00130164 +#define VID_B_VLD_MISC 0x00130168 +#define VID_B_TS_CLK_EN 0x0013016C +#define VID_B_VIP_CTRL 0x00130180 +#define VID_B_PIXEL_FRMT 0x00130184 + +/* Video C Interface */ +#define VID_C_GPCNT 0x00130220 +#define VID_C_GPCNT_CTL 0x00130230 +#define VBI_C_GPCNT_CTL 0x00130234 +#define VID_C_DMA_CTL 0x00130240 +#define VID_C_LNGTH 0x00130250 +#define VID_C_HW_SOP_CTL 0x00130254 +#define VID_C_GEN_CTL 0x00130258 +#define VID_C_BD_PKT_STATUS 0x0013025C +#define VID_C_SOP_STATUS 0x00130260 +#define VID_C_FIFO_OVFL_STAT 0x00130264 +#define VID_C_VLD_MISC 0x00130268 +#define VID_C_TS_CLK_EN 0x0013026C + +/* Internal Audio Interface */ +#define AUD_INT_A_GPCNT 0x00140020 +#define AUD_INT_B_GPCNT 0x00140024 +#define AUD_INT_A_GPCNT_CTL 0x00140030 +#define AUD_INT_B_GPCNT_CTL 0x00140034 +#define AUD_INT_DMA_CTL 0x00140040 +#define AUD_INT_A_LNGTH 0x00140050 +#define AUD_INT_B_LNGTH 0x00140054 +#define AUD_INT_A_MODE 0x00140058 +#define AUD_INT_B_MODE 0x0014005C + +/* External Audio Interface */ +#define AUD_EXT_DMA 0x00140100 +#define AUD_EXT_GPCNT 0x00140120 +#define AUD_EXT_GPCNT_CTL 0x00140130 +#define AUD_EXT_DMA_CTL 0x00140140 +#define AUD_EXT_LNGTH 0x00140150 +#define AUD_EXT_A_MODE 0x00140158 + +/* I2C Bus 1 */ +#define I2C1_ADDR 0x00180000 +#define I2C1_WDATA 0x00180004 +#define I2C1_CTRL 0x00180008 +#define I2C1_RDATA 0x0018000C +#define I2C1_STAT 0x00180010 + +/* I2C Bus 2 */ +#define I2C2_ADDR 0x00190000 +#define I2C2_WDATA 0x00190004 +#define I2C2_CTRL 0x00190008 +#define I2C2_RDATA 0x0019000C +#define I2C2_STAT 0x00190010 + +/* I2C Bus 3 */ +#define I2C3_ADDR 0x001A0000 +#define I2C3_WDATA 0x001A0004 +#define I2C3_CTRL 0x001A0008 +#define I2C3_RDATA 0x001A000C +#define I2C3_STAT 0x001A0010 + +/* UART */ +#define UART_CTL 0x001B0000 +#define UART_BRD 0x001B0004 +#define UART_ISR 0x001B000C +#define UART_CNT 0x001B0010 + +#endif /* _CX23885_REG_H_ */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h new file mode 100644 index 000000000000..f58ab86bd532 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885.h @@ -0,0 +1,295 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "btcx-risc.h" +#include "cx23885-reg.h" + +#include +#include + +#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) + +#define UNSET (-1U) + +#define CX23885_MAXBOARDS 8 + +#define SRAM 0 + +/* Max number of inputs by card */ +#define MAX_CX23885_INPUT 8 + +//#define SHADOW_MAX 3 + +#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ + +#define CX23885_BOARD_NOAUTO UNSET +#define CX23885_BOARD_UNKNOWN 0 +#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 +#define CX23885_BOARD_HAUPPAUGE_HVR1800 2 + +enum cx23885_itype { + CX23885_VMUX_COMPOSITE1 = 1, + CX23885_VMUX_COMPOSITE2, + CX23885_VMUX_COMPOSITE3, + CX23885_VMUX_COMPOSITE4, + CX23885_VMUX_SVIDEO, + CX23885_VMUX_TELEVISION, + CX23885_VMUX_CABLE, + CX23885_VMUX_DVB, + CX23885_VMUX_DEBUG, + CX23885_RADIO, +}; + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +/* buffer for one video frame */ +struct cx23885_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx23885 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + struct cx23885_fmt *fmt; + u32 count; +}; + +struct cx23885_input { + enum cx23885_itype type; + unsigned int vmux; + u32 gpio0, gpio1, gpio2, gpio3; +}; + +struct cx23885_board { + char *name; + enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB + } portc; + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; + struct cx23885_input input[MAX_CX23885_INPUT]; +}; + +struct cx23885_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +struct cx23885_i2c { + struct cx23885_dev *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* 885 registers used for raw addess */ + u32 i2c_period; + u32 reg_ctrl; + u32 reg_stat; + u32 reg_addr; + u32 reg_rdata; + u32 reg_wdata; +}; + +struct cx23885_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx23885_tsport { + struct cx23885_dev *dev; + + int nr; + int sram_chno; + + struct videobuf_dvb dvb; + + /* dma queues */ + struct cx23885_dmaqueue mpegq; + u32 ts_packet_size; + u32 ts_packet_count; + + int width; + int height; + + spinlock_t slock; + + /* registers */ + u32 reg_gpcnt; + u32 reg_gpcnt_ctl; + u32 reg_dma_ctl; + u32 reg_lngth; + u32 reg_hw_sop_ctrl; + u32 reg_gen_ctrl; + u32 reg_bd_pkt_status; + u32 reg_sop_status; + u32 reg_fifo_ovfl_stat; + u32 reg_vld_misc; + u32 reg_ts_clk_en; + u32 reg_ts_int_msk; + + /* Default register vals */ + int pci_irqmask; + u32 dma_ctl_val; + u32 ts_int_msk_val; + u32 gen_ctrl_val; + u32 ts_clk_en_val; +}; + +struct cx23885_dev { + struct list_head devlist; + atomic_t refcount; + + /* pci stuff */ + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + int pci_bus, pci_slot; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + //u32 shadow[SHADOW_MAX]; + int pci_irqmask; + + /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + struct cx23885_i2c i2c_bus[3]; + + int nr; + struct mutex lock; + + /* board details */ + unsigned int board; + char name[32]; + + struct cx23885_tsport ts2; + + /* sram configuration */ + struct sram_channel *sram_channels; +}; + +#define SRAM_CH01 0 /* Video A */ +#define SRAM_CH02 1 /* VBI A */ +#define SRAM_CH03 2 /* Video B */ +#define SRAM_CH04 3 /* Transport via B */ +#define SRAM_CH05 4 /* VBI B */ +#define SRAM_CH06 5 /* Video C */ +#define SRAM_CH07 6 /* Transport via C */ +#define SRAM_CH08 7 /* Audio Internal A */ +#define SRAM_CH09 8 /* Audio Internal B */ +#define SRAM_CH10 9 /* Audio External */ +#define SRAM_CH11 10 /* COMB_3D_N */ +#define SRAM_CH12 11 /* Comb 3D N1 */ +#define SRAM_CH13 12 /* Comb 3D N2 */ +#define SRAM_CH14 13 /* MOE Vid */ +#define SRAM_CH15 14 /* MOE RSLT */ + +struct sram_channel { + char *name; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start;; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; + u32 jumponly; +}; + +/* ----------------------------------------------------------- */ + +#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) +#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2)) + +#define cx_andor(reg,mask,value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) + +#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) +#define cx_clear(reg,bit) cx_andor((reg),(bit),0) + + +extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ + +extern struct cx23885_board cx23885_boards[]; +extern const unsigned int cx23885_bcount; + +extern struct cx23885_subid cx23885_subids[]; +extern const unsigned int cx23885_idcount; + +extern void cx23885_card_list(struct cx23885_dev *dev); +extern void cx23885_card_setup(struct cx23885_dev *dev); +extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); + +extern int cx23885_dvb_register(struct cx23885_tsport *port); +extern int cx23885_dvb_unregister(struct cx23885_tsport *port); + +extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field); + +extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); + +/* ----------------------------------------------------------- */ +/* cx23885-i2c.c */ +extern int cx23885_i2c_register(struct cx23885_i2c *bus); +extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ From 2f52cdb20955b024e6b48f4e3d797504c8568a6d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:55:18 -0300 Subject: [PATCH 183/310] V4L/DVB (6151): include drivers/media/video/cx23885/Kconfig Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 04756c342cba..5d74925748c0 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -668,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI source "drivers/media/video/cx88/Kconfig" +source "drivers/media/video/cx23885/Kconfig" + source "drivers/media/video/ivtv/Kconfig" config VIDEO_M32R_AR From 03121f05f98cf9bba8f0fe77ef381c17681e1386 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:57:52 -0300 Subject: [PATCH 184/310] V4L/DVB (6152): cx23885: forward compatibility fixes for recent kernels - fix #include for - fix cx23885_irq declaration for 2.6.19 and later Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- drivers/media/video/cx23885/cx23885.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 876d396fb7a3..4e6e8737e38e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1361,7 +1361,7 @@ static void cx23885_timeout(unsigned long data) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index f58ab86bd532..769a0e7541c0 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,7 +28,9 @@ #include #include #include +#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include +#endif #include "btcx-risc.h" #include "cx23885-reg.h" From a2129af5b65e28dc3a10402603aa714e493b2169 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 16 Mar 2007 11:48:33 -0300 Subject: [PATCH 185/310] V4L/DVB (6153): I2C bus 3 register was incorrect I2C bus 3 was being initialised with the incorrect address register. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4e6e8737e38e..fda0c1631dbd 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -722,7 +722,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].dev = dev; dev->i2c_bus[2].reg_stat = I2C3_STAT; dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; - dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_addr = I2C3_ADDR; dev->i2c_bus[2].reg_rdata = I2C3_RDATA; dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ From 3bd4065961aa03d030cd58feec03d60479fc4348 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 17:46:03 -0300 Subject: [PATCH 186/310] V4L/DVB (6154): NMI hang and corrupt transport packet fixes The sram allocations for the cx23887 differ slightly from the cx23885. This patch modifies the cx23887 specific sram memory map to reflect this. As a result, interrupts and DMA handling have also been enabled in cx23885_start_dma() for 887 specific boards. ATSC streaming is now available on cx23885 and cx23887 bridges. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fda0c1631dbd..5769db47529c 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -270,7 +270,7 @@ struct sram_channel cx23887_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x10480, + .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -1095,16 +1095,13 @@ static int cx23885_start_dma(struct cx23885_tsport *port, */ switch(cx23885_boards[dev->board].bridge) { case CX23885_BRIDGE_885: + case CX23885_BRIDGE_887: /* enable irqs */ dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); cx_set(port->reg_dma_ctl, port->dma_ctl_val); cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; - case CX23885_BRIDGE_887: - // FIXME - dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); - break; default: // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); From 3328e4fbf10a2c2513d4de662ab251e0f4cb7c3e Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:01:07 -0300 Subject: [PATCH 187/310] V4L/DVB (6155): Cleanup/remove code to access the sram memory maps The cx23885 and cx23887 family use two different memory maps which govern how the internal SRAM is configured. This patch streamlines the access to those structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 77 +--------------------- drivers/media/video/cx23885/cx23885.h | 2 - 2 files changed, 3 insertions(+), 76 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 5769db47529c..b1f75350e83d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -584,7 +584,6 @@ void cx23885_reset(struct cx23885_dev *dev) mdelay(100); -#if SRAM cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); @@ -595,37 +594,6 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - switch(dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ @@ -1019,38 +987,14 @@ static int cx23885_start_dma(struct cx23885_tsport *port, dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, buf->vb.width, buf->vb.height, buf->vb.field); -#if SRAM /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[ port->sram_chno ], port->ts_packet_size, buf->risc.dma); - if(debug > 5) + if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, - &cx23885_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, - &cx23887_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - - if(debug > 5) cx23885_risc_disasm(port, &buf->risc); + } /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); @@ -1323,18 +1267,8 @@ static void cx23885_timeout(unsigned long data) dprintk(1, "%s()\n",__FUNCTION__); if (debug > 5) -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - { - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); - } -#endif + cx23885_stop_dma(port); do_cancel_buffers(port, "timeout", 1); } @@ -1431,12 +1365,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); -#endif - } else if (ts2_status & VID_C_MSK_RISCI1) { diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 769a0e7541c0..04105bcf53f3 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -44,8 +44,6 @@ #define CX23885_MAXBOARDS 8 -#define SRAM 0 - /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 From 0fc0739ba940c07e97599a7ee04c24faae9808ed Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:03:03 -0300 Subject: [PATCH 188/310] V4L/DVB (6156): Added the I2C_FUNC_I2C support to the cx23885 i2c algo definition This is required to support the cx258xx family of audio and video decoders. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6f5e207c11a6..dbd048d08dda 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -279,7 +279,7 @@ static int cx23885_algo_control(struct i2c_adapter *adap, static u32 cx23885_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static struct i2c_algorithm cx23885_i2c_algo_template = { From e133be0f587996f112d7984c03606af418a7ca05 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 19:22:41 -0300 Subject: [PATCH 189/310] V4L/DVB (6157): Removed the need to manually define .bridge for each card Moved the field from cx23885_board to cx23885_dev and added code to iautomatically set the bridge type based on the pci device id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 --- drivers/media/video/cx23885/cx23885-core.c | 24 ++++++++++----------- drivers/media/video/cx23885/cx23885.h | 11 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 9344fb5d95f6..decf602ab164 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -32,7 +32,6 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", - .bridge = CX23885_BRIDGE_UNDEFINED, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, @@ -49,7 +48,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { .name = "Hauppauge WinTV-HVR1800lp", - .bridge = CX23885_BRIDGE_885, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, @@ -71,7 +69,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", - .bridge = CX23885_BRIDGE_887, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index b1f75350e83d..d8e376dee68b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -452,8 +452,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, cx_write(ch->cnt2_reg, (lines*16) >> 3); cx_write(ch->cnt1_reg, (bpl >> 3) -1); - dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", - cx23885_boards[dev->board].bridge, + dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n", + dev->bridge, ch->name, bpl, lines); @@ -770,18 +770,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the hardware internal memory for fifos */ - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_UNDEFINED: - case CX23885_BRIDGE_885: - dev->sram_channels = cx23885_sram_channels; - break; - case CX23885_BRIDGE_887: + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; } + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -1037,7 +1035,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, * starting or stopping interrupts or dma. Avoid the bug for the time being, * enabling the developer to work on the demod/tuner locking work. */ - switch(cx23885_boards[dev->board].bridge) { + switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: /* enable irqs */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 04105bcf53f3..4e1fc68d4206 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -101,11 +101,6 @@ struct cx23885_board { CX23885_MPEG_UNDEFINED = 0, CX23885_MPEG_DVB } portc; - enum { - CX23885_BRIDGE_UNDEFINED = 0, - CX23885_BRIDGE_885 = 885, - CX23885_BRIDGE_887 = 887, - } bridge; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -210,6 +205,12 @@ struct cx23885_dev { /* sram configuration */ struct sram_channel *sram_channels; + + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; }; #define SRAM_CH01 0 /* Video A */ From fe475163ff9680495af3b1b5b7633ea7a42e4185 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:27:53 -0300 Subject: [PATCH 190/310] V4L/DVB (6158): Fix MT2131 tuner lock status problem The mt2131 tuner reports lock even when the hardware should not lock. This patch allows the s5h1409 demodulator to be configured to query either the tuner driver for status, or the demodulator status when the application requests lock status. This avoids returning false CARRIER and/or SIGNAL lock status. S5H1409 and MT2131 drivers. This is the remainder of the changeset, which only touches cx23885-dvb.c Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 4ff85f75f9f7..188a5a7819cb 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -84,7 +84,8 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; static struct s5h1409_config hauppauge_hvr1800_config = { @@ -92,7 +93,8 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; From 047646bfbbe5ec961d2430514ae29fa0b87ab651 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:33:53 -0300 Subject: [PATCH 191/310] V4L/DVB (6159): General code cleanup Removed if 0'd code, removed cx88 references. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 6 +++--- drivers/media/video/cx23885/cx23885.h | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d8e376dee68b..804ba7ff9770 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1498,9 +1498,9 @@ static struct pci_driver cx23885_pci_driver = { static int cx23885_init(void) { printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); + (CX23885_VERSION_CODE >> 16) & 0xff, + (CX23885_VERSION_CODE >> 8) & 0xff, + CX23885_VERSION_CODE & 0xff); #ifdef SNAPSHOT printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4e1fc68d4206..b60de21c2387 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -38,7 +38,7 @@ #include #include -#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) +#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1) #define UNSET (-1U) @@ -69,14 +69,6 @@ enum cx23885_itype { CX23885_RADIO, }; -struct cx23885_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ From 70ebd70573a58a2c0405ef038f1acf74c795eaa5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 21:32:12 -0300 Subject: [PATCH 192/310] V4L/DVB (6161): cx23885-dvb.c doesnt need to include dvb-pll.h The dvb-pll module is not being used by this driver. Remove the unneeded #include. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 188a5a7819cb..79948553901d 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -28,7 +28,6 @@ #include #include "cx23885.h" -#include "dvb-pll.h" #include #include "s5h1409.h" From 44a6481dcd9ec835bbd608b1b2ee47ee62c7e1d8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:00:18 -0300 Subject: [PATCH 193/310] V4L/DVB (6162): cx23885: whitespace cleanups Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 +- drivers/media/video/cx23885/cx23885-core.c | 273 +++++++++++--------- drivers/media/video/cx23885/cx23885-dvb.c | 59 +++-- drivers/media/video/cx23885/cx23885-i2c.c | 40 +-- drivers/media/video/cx23885/cx23885.h | 17 +- 5 files changed, 210 insertions(+), 182 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index decf602ab164..8bb3fe4a876c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -171,7 +171,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) { dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + tveeprom_read(&dev->i2c_bus[0].i2c_client, + eeprom, sizeof(eeprom)); } switch (dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 804ba7ff9770..6f0a8dbc6b3b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -349,15 +349,15 @@ static int cx23885_risc_decode(u32 risc) printk("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); + printk(" %s", bits[i]); printk(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -374,7 +374,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, if ((s16) (count - buf->count) < 0) break; do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); @@ -383,31 +383,34 @@ void cx23885_wakeup(struct cx23885_tsport *port, if (list_empty(&q->active)) { del_timer(&q->timeout); } else { - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); } if (bc != 1) - printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); + printk("%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); + struct sram_channel *ch); int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) + struct sram_channel *ch, + unsigned int bpl, u32 risc) { - unsigned int i,lines; + unsigned int i, lines; u32 cdt; if (ch->cmds_start == 0) { - dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__, + ch->name); cx_write(ch->ptr1_reg, 0); cx_write(ch->ptr2_reg, 0); cx_write(ch->cnt2_reg, 0); cx_write(ch->cnt1_reg, 0); return 0; } else { - dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__, + ch->name); } bpl = (bpl + 7) & ~7; /* alignment */ @@ -417,13 +420,14 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); - cx_write(8+4, cpu_to_le32(8) ); - cx_write(8+8, cpu_to_le32(0) ); + cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8 + 4, cpu_to_le32(8) ); + cx_write(8 + 8, cpu_to_le32(0) ); /* write CDT */ for (i = 0; i < lines; i++) { - dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, + ch->fifo_start + bpl*i); cx_write(cdt + 16*i, ch->fifo_start + bpl*i); cx_write(cdt + 16*i + 4, 0); cx_write(cdt + 16*i + 8, 0); @@ -462,7 +466,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -481,7 +485,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, "line / byte", }; u32 risc; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: %s - dma channel status dump\n", dev->name, ch->name); @@ -491,16 +495,19 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, cx_read(ch->cmds_start + 4*i)); for (i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i+14)); + risc = cx_read(ch->cmds_start + 4 * (i + 14)); printk("%s: risc%d: ", dev->name, i); cx23885_risc_decode(risc); } for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ - printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + printk("%s: (0x%08x) iq %x: ", dev->name, + ch->ctrl_start + 4 * i, i); n = cx23885_risc_decode(risc); for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i+j)); + risc = cx_read(ch->ctrl_start + 4 * (i + j)); printk("%s: iq %x: 0x%08x [ arg #%d ]\n", dev->name, i+j, risc, j); } @@ -509,7 +516,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, printk("%s: fifo: 0x%08x -> 0x%x\n", dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); printk("%s: ctrl: 0x%08x -> 0x%x\n", - dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); printk("%s: ptr1_reg: 0x%08x\n", dev->name, cx_read(ch->ptr1_reg)); printk("%s: ptr2_reg: 0x%08x\n", @@ -520,10 +527,11 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: risc disasm: %p [dma=0x%08lx]\n", dev->name, risc->cpu, (unsigned long)risc->dma); @@ -532,7 +540,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) n = cx23885_risc_decode(risc->cpu[i]); for (j = 1; j < n; j++) printk("%s: %04d: 0x%08x [ arg #%d ]\n", - dev->name, i+j, risc->cpu[i+j], j); + dev->name, i + j, risc->cpu[i + j], j); if (risc->cpu[i] == RISC_JUMP) break; } @@ -625,8 +633,8 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) static int get_resources(struct cx23885_dev *dev) { if (request_mem_region(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0), - dev->name)) + pci_resource_len(dev->pci,0), + dev->name)) return 0; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", @@ -637,7 +645,7 @@ static int get_resources(struct cx23885_dev *dev) static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); + u32 reg, u32 mask, u32 value); static int cx23885_ir_init(struct cx23885_dev *dev) { @@ -726,15 +734,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - sprintf(dev->name,"cx23885[%d]", dev->nr); + sprintf(dev->name, "cx23885[%d]", dev->nr); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); cx23885_devcount--; goto fail_free; @@ -746,7 +755,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0)); + pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; @@ -765,10 +774,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx23885_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); /* Configure the internal memory */ if(dev->pci->device == 0x8880) { @@ -779,7 +788,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -793,7 +803,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + printk(KERN_ERR "%s() Failed to register dvb adapters\n", + __FUNCTION__); } return 0; @@ -820,12 +831,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) } static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line, todo; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -874,11 +885,11 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, } int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines) + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) { - u32 instructions,fields; + u32 instructions, fields; u32 *rp; int rc; @@ -903,10 +914,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -915,8 +926,8 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -945,7 +956,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -969,7 +980,7 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(&buf->vb, 0, 0); videobuf_dma_unmap(q, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); @@ -977,18 +988,18 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) } static int cx23885_start_dma(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) { struct cx23885_dev *dev = port->dev; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, - buf->vb.width, buf->vb.height, buf->vb.field); + buf->vb.width, buf->vb.height, buf->vb.field); /* setup fifo + format */ cx23885_sram_channel_setup(dev, - &dev->sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); cx23885_risc_disasm(port, &buf->risc); @@ -998,8 +1009,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_lngth, buf->vb.width); if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, - cx23885_boards[dev->board].portc ); + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", + __FUNCTION__, cx23885_boards[dev->board].portc ); return -EINVAL; } @@ -1017,7 +1028,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", + __FUNCTION__); break; default: // FIXME @@ -1103,53 +1115,54 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; + struct cx23885_buffer *prev; + prev = NULL; dprintk(5, "%s() queue is empty\n", __FUNCTION__); - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ - dprintk(5,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item,&q->active) { + list_for_each(item, &q->active) { buf = list_entry(item, struct cx23885_buffer, vb.queue); buf->count = q->count++; } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } @@ -1172,7 +1185,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, buf->vb.size = size; buf->vb.field = field /*V4L2_FIELD_TOP*/; - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, @@ -1182,7 +1195,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, return 0; fail: - cx23885_free_buffer(q,buf); + cx23885_free_buffer(q, buf); return rc; } @@ -1199,51 +1212,53 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) if (list_empty(&cx88q->active)) { dprintk( 1, "queue is empty - first active\n" ); - list_add_tail(&buf->vb.queue,&cx88q->active); + list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] %s - first active\n", + mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); } else { dprintk( 1, "queue is not empty - append to active\n" ); - prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); - list_add_tail(&buf->vb.queue,&cx88q->active); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &cx88q->active); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk( 1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __FUNCTION__); + buf, buf->vb.i, __FUNCTION__); } } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, + int restart) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; struct cx23885_buffer *buf; unsigned long flags; - spin_lock_irqsave(&port->slock,flags); + spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); - dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); } - if (restart) - { + if (restart) { dprintk(1, "restarting queue\n" ); cx23885_restart_queue(port, q); } - spin_unlock_irqrestore(&port->slock,flags); + spin_unlock_irqrestore(&port->slock, flags); } void cx23885_cancel_buffers(struct cx23885_tsport *port) @@ -1251,7 +1266,7 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; - dprintk(1, "%s()\n", __FUNCTION__ ); + dprintk(1, "%s()\n", __FUNCTION__); del_timer_sync(&q->timeout); cx23885_stop_dma(port); do_cancel_buffers(port, "cancel", 0); @@ -1312,15 +1327,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || - (pci_status & PCI_MSK_RISC_WR) || - (pci_status & PCI_MSK_AL_RD) || - (pci_status & PCI_MSK_AL_WR) || - (pci_status & PCI_MSK_APB_DMA) || - (pci_status & PCI_MSK_VID_C) || - (pci_status & PCI_MSK_VID_B) || - (pci_status & PCI_MSK_VID_A) || - (pci_status & PCI_MSK_AUD_INT) || - (pci_status & PCI_MSK_AUD_EXT) ) + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) { if (pci_status & PCI_MSK_RISC_RD) @@ -1347,9 +1362,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) { if (ts2_status & VID_C_MSK_OPC_ERR) dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); @@ -1392,12 +1407,12 @@ out: } static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) + const struct pci_device_id *pci_id) { struct cx23885_dev *dev; int err; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; @@ -1428,8 +1443,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = request_irq(pci_dev->irq, cx23885_irq - , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, pci_dev->irq); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 79948553901d..bd0afc2a0447 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -53,11 +53,11 @@ static int dvb_buf_setup(struct videobuf_queue *q, return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field); } static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) @@ -66,7 +66,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) cx23885_buf_queue(port, (struct cx23885_buffer*)vb); } -static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) { cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } @@ -116,26 +117,22 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, 0); } break; default: @@ -152,7 +149,8 @@ static int dvb_register(struct cx23885_tsport *port) cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ - return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, + &dev->pci->dev); } int cx23885_dvb_register(struct cx23885_tsport *port) @@ -160,8 +158,8 @@ int cx23885_dvb_register(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; int err; - dprintk( 1, "%s\n", __FUNCTION__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, "%s\n", __FUNCTION__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", dev->board, dev->name, dev->pci_bus, @@ -173,15 +171,9 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init( - &port->dvb.dvbq, - &dvb_qops, - dev->pci, - &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), - port); + videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), port); err = dvb_register(port); if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); @@ -198,3 +190,10 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off +*/ diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index dbd048d08dda..155ab928cd60 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -31,11 +31,11 @@ static unsigned int i2c_debug = 2; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) @@ -76,7 +76,8 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) return 1; } -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -150,11 +151,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -206,11 +208,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -219,8 +222,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); for (i = 0 ; i < num; i++) { - dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" - , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); @@ -261,7 +264,8 @@ static int detach_inform(struct i2c_client *client) return 0; } -void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, + unsigned int cmd, void *arg) { // struct cx23885_dev *dev = bus->dev; @@ -316,11 +320,11 @@ static char *i2c_devs[128] = { static void do_i2c_scan(char *name, struct i2c_client *c) { unsigned char buf; - int i,rc; + int i, rc; for (i = 0; i < 128; i++) { c->addr = i; - rc = i2c_master_recv(c,&buf,0); + rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; printk("%s: i2c scan: found device @ 0x%x [%s]\n", @@ -335,13 +339,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); - memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, + sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, + sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, + sizeof(bus->i2c_client)); bus->i2c_adap.dev.parent = &dev->pci->dev; - strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + strlcpy(bus->i2c_adap.name, bus->dev->name, + sizeof(bus->i2c_adap.name)); bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b60de21c2387..4312c3fcc1ec 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -183,7 +183,7 @@ struct cx23885_dev { //u32 shadow[SHADOW_MAX]; int pci_irqmask; - /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; int nr; @@ -268,17 +268,22 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field); +extern int cx23885_buf_prepare(struct videobuf_queue *q, + struct cx23885_tsport *port, + struct cx23885_buffer *buf, + enum v4l2_field field); -extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); +extern void cx23885_buf_queue(struct cx23885_tsport *port, + struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, + struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); -extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, + void *arg); /* * Local variables: From 60a41d3b61a714d98a36cddbe182cc6ff0794274 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:03:52 -0300 Subject: [PATCH 194/310] V4L/DVB (6163): cx23885: remove old comments Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ---- drivers/media/video/cx23885/cx23885-i2c.c | 4 +--- drivers/media/video/cx23885/cx23885-reg.h | 11 ++--------- drivers/media/video/cx23885/cx23885.h | 3 --- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 6f0a8dbc6b3b..3e1b62a2d50d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1043,10 +1043,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; - /* A bug in the current 887 implementation, causes an NMI assert during - * starting or stopping interrupts or dma. Avoid the bug for the time being, - * enabling the developer to work on the demod/tuner locking work. - */ switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 155ab928cd60..c40c37f2d139 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -267,12 +267,10 @@ static int detach_inform(struct i2c_client *client) void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) { -// struct cx23885_dev *dev = bus->dev; - if (bus->i2c_rc != 0) return; - i2c_clients_command(&bus->i2c_adap, cmd, arg); + i2c_clients_command(&bus->i2c_adap, cmd, arg); } static int cx23885_algo_control(struct i2c_adapter *adap, diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 5cb692f20d28..771b22ac2153 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -71,21 +71,14 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 -//#define RISC_SYNC_ODD 0x80000000 -//#define RISC_SYNC_EVEN 0x80000200 -//#define RISC_RESYNC_ODD 0x80008000 -//#define RISC_RESYNC_EVEN 0x80008200 -// Do we need these? +/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -// Is this used? +/* Is this used? */ #define RISC_IMM 0x00000001 -//#define RISC_CNT_NONE 0x00000000 -//#define RISC_CNT_RSVR 0x00020000 -//#define RISC_JMP_SRP 0x01 /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4312c3fcc1ec..929235440e23 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -47,8 +47,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 -//#define SHADOW_MAX 3 - #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ #define CX23885_BOARD_NOAUTO UNSET @@ -180,7 +178,6 @@ struct cx23885_dev { int pci_bus, pci_slot; u32 __iomem *lmmio; u8 __iomem *bmmio; - //u32 shadow[SHADOW_MAX]; int pci_irqmask; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ From 3c5666aee31decafdca14f6f83d33ec27b27f982 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:18:04 -0300 Subject: [PATCH 195/310] V4L/DVB (6164): cx23885: turn off i2c_debug by default Turn off i2c_debug by default, to make the driver less verbose. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index c40c37f2d139..6b49b414aebf 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include -static unsigned int i2c_debug = 2; +static unsigned int i2c_debug = 0; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); From b86b580244511f9b2fb2043d813e9c4c7d294a62 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Mar 2007 01:01:53 -0300 Subject: [PATCH 196/310] V4L/DVB (6165): cx23885: fix Kconfig dependencies Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ea53466dacbe..333dd29d44b4 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -8,6 +8,9 @@ config VIDEO_CX23885 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_BUF_DVB + select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select DVB_S5H1409 if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. From 426d523664e01c778f6455e9b3bbd40dda76c66a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 14 Aug 2007 23:35:16 -0300 Subject: [PATCH 197/310] V4L/DVB (6166): cx23885: Ensure pci_quirks is called after board identification The pci_quirks function was being called too early during initialisation, it needs to be called after the board has been identified. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3e1b62a2d50d..691672947084 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -759,8 +759,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bmmio = (u8 __iomem *)dev->lmmio; - cx23885_pci_quirks(dev); - /* board config */ dev->board = UNSET; if (card[dev->nr] < cx23885_bcount) @@ -779,6 +777,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); + cx23885_pci_quirks(dev); + /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; From 4823e9ee9f45c78777d040742b5e46336a42c8b3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 20:52:21 -0300 Subject: [PATCH 198/310] V4L/DVB (6167): cx23885: Changed PCI quirks to after bridge detech Changed the pci_quirks function to detech the bridge type before setting the NMI clear bit, rather than detecting based on unique board id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 691672947084..d2bc3e586623 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -622,11 +622,9 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); - break; - } + return 0; } @@ -777,8 +775,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - cx23885_pci_quirks(dev); - /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; @@ -791,6 +787,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + cx23885_pci_quirks(dev); + /* init hardware */ cx23885_reset(dev); From a77743bc2d29197d48a6f4ae9f8f9e0f0b0ba5d7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 21:01:20 -0300 Subject: [PATCH 199/310] V4L/DVB (6168): cx23885: Added HVR1250 ATSC support Adding support for the Hauppauge HVR1250 PCIe ATSC board. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 26 +++++++++++++++++++++ drivers/media/video/cx23885/cx23885-core.c | 7 ++++++ drivers/media/video/cx23885/cx23885-dvb.c | 24 +++++++++++++++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 58 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 8bb3fe4a876c..e6d34fb5b943 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -88,6 +88,27 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_HAUPPAUGE_HVR1250] = { + .name = "Hauppauge WinTV-HVR1250", + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -111,6 +132,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7911, + .card = CX23885_BOARD_HAUPPAUGE_HVR1250, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -176,6 +201,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) } switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d2bc3e586623..1148d684188a 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -603,6 +603,11 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -650,6 +655,7 @@ static int cx23885_ir_init(struct cx23885_dev *dev) dprintk(1, "%s()\n", __FUNCTION__); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); break; @@ -1023,6 +1029,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(GPIO2, 0x00); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bd0afc2a0447..63a1dde0d17a 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -97,6 +97,16 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .status_mode = S5H1409_DEMODLOCKING }; +static struct s5h1409_config hauppauge_hvr1250_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + + static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 @@ -106,6 +116,10 @@ static struct mt2131_config hauppauge_hvr1800_tunerconfig = { 0x61 }; +static struct mt2131_config hauppauge_hvr1250_tunerconfig = { + 0x61 +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -115,6 +129,16 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1250_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1250_tunerconfig, 0); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 929235440e23..300a97980acb 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -53,6 +53,7 @@ #define CX23885_BOARD_UNKNOWN 0 #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 +#define CX23885_BOARD_HAUPPAUGE_HVR1250 3 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, From f29379c3619d85e0bdc0ee30c8199f7f66866fcf Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:15:46 -0300 Subject: [PATCH 200/310] V4L/DVB (6169): Removed unused function mt2131_set_gpo() Unused code is removed. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 6bcc4ccc9911..4b93931de4e1 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -91,17 +91,6 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) return 0; } -static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) -{ - struct mt2131_priv *priv = fe->tuner_priv; - u8 v; - - mt2131_readreg(priv, 0x07, &v); - mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); - - return 0; -} - static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { From 2e52f215be1b3a0337788c8d3345bdf5e3894e19 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:32:41 -0300 Subject: [PATCH 201/310] V4L/DVB (6170): cx23885: General cleanup of old code Removed unused code. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 1 - drivers/media/video/cx23885/cx23885-core.c | 40 ++------------------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +-- drivers/media/video/cx23885/cx23885-i2c.c | 3 +- drivers/media/video/cx23885/cx23885-reg.h | 9 ----- drivers/media/video/cx23885/cx23885.h | 1 - 6 files changed, 4 insertions(+), 54 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index e6d34fb5b943..09d4376c2e05 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -172,7 +172,6 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); - /* Make sure we support the board model */ switch (tv.model) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 1148d684188a..7a1c4672041d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -368,11 +368,13 @@ void cx23885_wakeup(struct cx23885_tsport *port, break; buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; + do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); @@ -910,7 +912,6 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 2; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -945,7 +946,6 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -970,7 +970,6 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); *(rp++) = cpu_to_le32(reg); *(rp++) = cpu_to_le32(value); @@ -1018,16 +1017,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, return -EINVAL; } - // FIXME: review the need for these two lines - dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); udelay(100); cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - // FIXME: review the need for this - cx_write(GPIO2, 0x00); - switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: @@ -1037,7 +1031,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, __FUNCTION__); break; default: - // FIXME printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } @@ -1058,39 +1051,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } - dprintk(1, "%s() Register Dump\n", __FUNCTION__); - dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); - dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); - dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); - dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); - dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); - dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); - dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); - dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); - dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); - dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); - dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); - cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ - dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); - dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); - dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); - dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); - dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); - dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); - dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); - dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); - dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); return 0; } @@ -1220,7 +1185,6 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); - } else { dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 63a1dde0d17a..58ae15a99e9c 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -33,7 +33,7 @@ #include "s5h1409.h" #include "mt2131.h" -static unsigned int debug = 2; +static unsigned int debug = 0; #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) @@ -106,8 +106,6 @@ static struct s5h1409_config hauppauge_hvr1250_config = { .status_mode = S5H1409_DEMODLOCKING }; - - static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 }; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6b49b414aebf..5572fbbbb5ae 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -130,7 +130,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (cnt < msg->len-1 || !last) ctrl |= I2C_NOSTOP | I2C_EXTEND; - //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); cx_write(bus->reg_ctrl, ctrl); @@ -297,7 +296,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, -// .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -348,6 +346,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 771b22ac2153..6527bd3b4d77 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -22,7 +22,6 @@ #ifndef _CX23885_REG_H_ #define _CX23885_REG_H_ - /* Address Map 0x00000000 -> 0x00009000 TX SRAM (Fifos) @@ -50,8 +49,6 @@ Channel manager Data Structure entry = 20 DWORD 5 InstructionQueueSize ... Reserved 19 Reserved - - */ /* Risc Instructions */ @@ -70,15 +67,9 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITERM 0xB0000000 #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 - - -/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -/* Is this used? */ -#define RISC_IMM 0x00000001 - /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 300a97980acb..c0f4e4337351 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -245,7 +245,6 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) - extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc); From 31bae4a62036a1d85aa9ee5864115dad2727336d Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:36:32 -0300 Subject: [PATCH 202/310] V4L/DVB (6171): cx23885: Cleaning up defines Moving some defines into the correct header file. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 19 ------------------- drivers/media/video/cx23885/cx23885-reg.h | 11 ++++++++++- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 7a1c4672041d..fa5f6488b994 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1251,25 +1251,6 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } -#define PCI_MSK_APB_DMA (1 << 12) -#define PCI_MSK_AL_WR (1 << 11) -#define PCI_MSK_AL_RD (1 << 10) -#define PCI_MSK_RISC_WR (1 << 9) -#define PCI_MSK_RISC_RD (1 << 8) - -#define PCI_MSK_AUD_EXT (1 << 4) -#define PCI_MSK_AUD_INT (1 << 3) -#define PCI_MSK_VID_C (1 << 2) -#define PCI_MSK_VID_B (1 << 1) -#define PCI_MSK_VID_A 1 - -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 - static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 6527bd3b4d77..63ab0fb26acb 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -211,7 +211,7 @@ Channel manager Data Structure entry = 20 DWORD #define I2S_TX_CFG 0x0000001A #define DEV_CNTRL2 0x00040000 -#define PCI_INT_MSK 0x00040010 + #define PCI_MSK_APB_DMA (1 << 12) #define PCI_MSK_AL_WR (1 << 11) #define PCI_MSK_AL_RD (1 << 10) @@ -222,6 +222,8 @@ Channel manager Data Structure entry = 20 DWORD #define PCI_MSK_VID_C (1 << 2) #define PCI_MSK_VID_B (1 << 1) #define PCI_MSK_VID_A 1 +#define PCI_INT_MSK 0x00040010 + #define PCI_INT_STAT 0x00040014 #define PCI_INT_MSTAT 0x00040018 @@ -235,7 +237,14 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 #define VID_C_INT_MSK 0x00040040 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) From 86184e06da4b71fc24ae9505ec60ce95c098d0de Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:40:47 -0300 Subject: [PATCH 203/310] V4L/DVB (6172): cx23885: Removing duplicate tuner and demod definitions A number of Hauppauge boards share the same tuner and demod configurations. This patch removes duplicate structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 54 +++-------------------- 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 58ae15a99e9c..291cc0556222 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -79,7 +79,7 @@ static struct videobuf_queue_ops dvb_qops = { .buf_release = dvb_buf_release, }; -static struct s5h1409_config hauppauge_hvr1800lp_config = { +static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -88,33 +88,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .status_mode = S5H1409_DEMODLOCKING }; -static struct s5h1409_config hauppauge_hvr1800_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct s5h1409_config hauppauge_hvr1250_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1800_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1250_tunerconfig = { +static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; @@ -128,33 +102,15 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1250_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1250_tunerconfig, 0); - } - break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, + &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, 0); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, 0); + &hauppauge_generic_tunerconfig, 0); } break; default: From 2df9a4c2d81ed255c9e027ee5df676a65f4ab578 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:50:49 -0300 Subject: [PATCH 204/310] V4L/DVB (6173): cx23885: Minor cleanup and important NMI comment placed in code I wanted to document the NMI assert issue inside the code, even though it's already documented in the patch history. If/when the next cx23887 revision appears, is may need to be enabled on that also. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fa5f6488b994..13dc7c8642ca 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -331,8 +331,8 @@ static int cx23885_risc_decode(u32 risc) [ RISC_WRITECR >> 28 ] = "writecr", }; static int incr[16] = { - [ RISC_WRITE >> 28 ] = 3, // 2 - [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_WRITE >> 28 ] = 3, + [ RISC_JUMP >> 28 ] = 3, [ RISC_SKIP >> 28 ] = 1, [ RISC_SYNC >> 28 ] = 1, [ RISC_WRITERM >> 28 ] = 3, @@ -629,6 +629,10 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); + /* The cx23885 bridge has a weird bug which causes NMI to be asserted + * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not + * occur on the cx23887 bridge. + */ if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); From d54d6980916d5521ad47fa61e5b6ff8733221714 Mon Sep 17 00:00:00 2001 From: Chaogui Zhang Date: Fri, 24 Aug 2007 01:02:32 -0300 Subject: [PATCH 205/310] V4L/DVB (6178): add IR remote support for FusionHDTV 5 RT Gold This patch adds support for the built-in IR receiver of the DViCO Fusion HDTV5 RT GOLD PCI card, using FusionHDTV MCE remote controller. Signed-off-by: Chaogui Zhang Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 69 +++++++++++++++++++++++++++++++ drivers/media/video/ir-kbd-i2c.c | 36 +++++++++++++++- include/media/ir-common.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 137f68bee39f..1879c304ae6d 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1782,3 +1782,72 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_tt_1500); + +/* DViCO FUSION HDTV 5 RT GOLD remote */ +IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { + + [ 0x0b ] = KEY_1, + [ 0x17 ] = KEY_2, + [ 0x1b ] = KEY_3, + [ 0x07 ] = KEY_4, + [ 0x50 ] = KEY_5, + [ 0x54 ] = KEY_6, + [ 0x48 ] = KEY_7, + [ 0x4c ] = KEY_8, + [ 0x58 ] = KEY_9, + [ 0x03 ] = KEY_0, + + [ 0x5e ] = KEY_OK, + [ 0x51 ] = KEY_UP, + [ 0x53 ] = KEY_DOWN, + [ 0x5b ] = KEY_LEFT, + [ 0x5f ] = KEY_RIGHT, + + [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ + [ 0x0e ] = KEY_MP3, + [ 0x1a ] = KEY_DVD, + [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x16 ] = KEY_SETUP, + [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ + [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ + + [ 0x49 ] = KEY_BACK, + [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ + [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ + [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ + [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + * MS windows logo on remote */ + + [ 0x15 ] = KEY_VOLUMEUP, + [ 0x05 ] = KEY_VOLUMEDOWN, + [ 0x11 ] = KEY_CHANNELUP, + [ 0x09 ] = KEY_CHANNELDOWN, + + /* The following are not defined in kernel 2.6 and + * I cannot find suitable substitute key definitions. + + [ 0x52 ] = KEY_PHOTO, + [ 0x5a ] = KEY_LIVE, + [ 0x19 ] = KEY_FOLDER, + + */ + + [ 0x52 ] = KEY_RESERVED, + [ 0x5a ] = KEY_RESERVED, + [ 0x19 ] = KEY_RESERVED, + + [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ + [ 0x1f ] = KEY_ZOOM, + + [ 0x43 ] = KEY_REWIND, + [ 0x47 ] = KEY_PLAYPAUSE, + [ 0x4f ] = KEY_FORWARD, + [ 0x57 ] = KEY_MUTE, + [ 0x0d ] = KEY_STOP, + [ 0x01 ] = KEY_RECORD, + [ 0x4e ] = KEY_POWER, +}; + +EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index b3939a0bada0..3d5a28c2c929 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -10,6 +10,8 @@ * Ulrich Mueller * modified for em2820 based USB TV tuners by * Markus Rechberger + * modified for DViCO Fusion HDTV 5 RT GOLD by + * Chaogui Zhang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -141,6 +143,32 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[4]; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c,buf,4)) { + dprintk(1,"read error\n"); + return -EIO; + } + + if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) + dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + buf[0], buf[1], buf[2], buf[3]); + + /* no key pressed or signal from other ir remote */ + if(buf[0] != 0x1 || buf[1] != 0xfe) + return 0; + + *ir_key = buf[2]; + *ir_raw = (buf[2] << 8) | buf[3]; + + return 1; + +} + + static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -363,6 +391,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_type = IR_TYPE_OTHER; ir_codes = ir_codes_empty; break; + case 0x6b: + name = "FusionGold"; + ir->get_key = get_key_fusion_gold; + ir_type = IR_TYPE_RC5; + ir_codes = ir_codes_fusion_gold; + break; case 0x7a: case 0x47: case 0x71: @@ -474,7 +508,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x71, -1 }; + static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 9807a7c15830..dfae84038e2d 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; #endif From 3c44358c49ee4142d0f868509b5b3b02759fa16a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:07:12 -0300 Subject: [PATCH 206/310] V4L/DVB (6179): Clean up FusionHDTV ir code - fixed missing buttons in keymap. - make function names & descriptions more generic, since this same ir receiver and remote is used in many FusionHDTV products. - miscellaneous cleanups. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 32 ++++++++++++------------------- drivers/media/video/ir-kbd-i2c.c | 12 +++++------- include/media/ir-common.h | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 1879c304ae6d..aefcf28da1ca 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1783,8 +1783,8 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_tt_1500); -/* DViCO FUSION HDTV 5 RT GOLD remote */ -IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { +/* DViCO FUSION HDTV MCE remote */ +IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { [ 0x0b ] = KEY_1, [ 0x17 ] = KEY_2, @@ -1806,7 +1806,7 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ [ 0x0e ] = KEY_MP3, [ 0x1a ] = KEY_DVD, - [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */ [ 0x16 ] = KEY_SETUP, [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ @@ -1815,9 +1815,10 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ - [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ - [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ - [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + + [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_ENTER, /* Labeled START with a green * MS windows logo on remote */ [ 0x15 ] = KEY_VOLUMEUP, @@ -1825,29 +1826,20 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x11 ] = KEY_CHANNELUP, [ 0x09 ] = KEY_CHANNELDOWN, - /* The following are not defined in kernel 2.6 and - * I cannot find suitable substitute key definitions. - - [ 0x52 ] = KEY_PHOTO, - [ 0x5a ] = KEY_LIVE, - [ 0x19 ] = KEY_FOLDER, - - */ - - [ 0x52 ] = KEY_RESERVED, - [ 0x5a ] = KEY_RESERVED, - [ 0x19 ] = KEY_RESERVED, + [ 0x52 ] = KEY_CAMERA, + [ 0x5a ] = KEY_TUNER, + [ 0x19 ] = KEY_OPEN, [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ [ 0x1f ] = KEY_ZOOM, [ 0x43 ] = KEY_REWIND, [ 0x47 ] = KEY_PLAYPAUSE, - [ 0x4f ] = KEY_FORWARD, + [ 0x4f ] = KEY_FASTFORWARD, [ 0x57 ] = KEY_MUTE, [ 0x0d ] = KEY_STOP, [ 0x01 ] = KEY_RECORD, [ 0x4e ] = KEY_POWER, }; -EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); +EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3d5a28c2c929..04f6eb5ea292 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -143,7 +143,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[4]; @@ -154,7 +154,7 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); /* no key pressed or signal from other ir remote */ @@ -165,10 +165,8 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) *ir_raw = (buf[2] << 8) | buf[3]; return 1; - } - static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -392,10 +390,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_empty; break; case 0x6b: - name = "FusionGold"; - ir->get_key = get_key_fusion_gold; + name = "FusionHDTV"; + ir->get_key = get_key_fusionhdtv; ir_type = IR_TYPE_RC5; - ir_codes = ir_codes_fusion_gold; + ir_codes = ir_codes_fusionhdtv_mce; break; case 0x7a: case 0x47: diff --git a/include/media/ir-common.h b/include/media/ir-common.h index dfae84038e2d..7a785fa77212 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,7 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; #endif From a1dec5160d6e536b409761c1914500f4a7cf08c2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:13:07 -0300 Subject: [PATCH 207/310] V4L/DVB (6180): tuner: don't probe 0x6b or 0x6f on cx88 boards Ignore 0x6b and 0x6f on cx88 boards. Some FusionHDTV cards have an ir receiver at 0x6b and an RTC at 0x6f which can get corrupted if probed. Signed-off-by: Michael Krufky Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2f74379f4e4b..2d4a3e38f278 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -661,6 +661,27 @@ static int tuner_probe(struct i2c_adapter *adap) normal_i2c[1] = I2C_CLIENT_END; } + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if (adap->id == I2C_HW_B_CX2388x) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; if (adap->class & I2C_CLASS_TV_ANALOG) From 6fcecce7e1a5223be450031fa446323b08d1ec41 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:32:31 -0300 Subject: [PATCH 208/310] V4L/DVB (6181): cx88: auto-load rtc and ir receiver i2c modules for FusionHDTV5 RT Gold Auto-load ir-kbd-i2c for ir receiver support, and rtc-isl1208 for rtc support for the FusionHDTV5 RT Gold. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index a16fc157a67d..f94a3b41782a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1831,6 +1831,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + request_module("ir-kbd-i2c"); + request_module("rtc-isl1208"); + } + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); From 82896f29d47d945e331873c7295da9e3a47d709d Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:23 -0300 Subject: [PATCH 209/310] V4L/DVB (6184): cx88-alsa: Make volume control stereo Use the balance control to make the mono volume control stereo. Note that full range isn't supported. The balance control attenuates one channel by 0 to -63 dB, and the volume control provides additional attenuation to both channels by another 0 to -63 dB. So the channel with the most attenuation has a range of 0 to -126 dB, while the other channel only has a range of 0 to -63 dB. ALSA volume controls don't appear to support this concept. I just limited the range to 0 to -63 total. Once you get to -63 dB, you're already at silence, so additional attenuation is pretty much pointless anyway. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 59 +++++++++++++++++----------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 85d632224f3a..25de25fb8052 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -552,7 +552,7 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; + info->count = 2; info->value.integer.min = 0; info->value.integer.max = 0x3f; @@ -565,8 +565,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; + int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), + bal = cx_read(AUD_BAL_CTL); - value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; + vol -= (bal & 0x3f); + value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; return 0; } @@ -577,19 +581,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; - int v; - u32 old_control; + int v, b; + int changed = 0; + u32 old; + b = value->value.integer.value[1] - value->value.integer.value[0]; + if (b < 0) { + v = 0x3f - value->value.integer.value[0]; + b = (-b) | 0x40; + } else { + v = 0x3f - value->value.integer.value[1]; + } /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); - - old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); - v = 0x3f - (value->value.integer.value[0] & 0x3f); - cx_andor(AUD_VOL_CTL, 0x3f, v); - + old = cx_read(AUD_VOL_CTL); + if (v != (old & 0x3f)) { + cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; + } + if (cx_read(AUD_BAL_CTL) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; + } spin_unlock_irq(&chip->reg_lock); - return v != old_control; + return changed; } static struct snd_kcontrol_new snd_cx88_capture_volume = { @@ -746,17 +762,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, return (err); err = snd_cx88_pcm(chip, 0, "CX88 Digital"); - - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; strcpy (card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); @@ -768,14 +779,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->driver,devno); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; pci_set_drvdata(pci,card); devno++; return 0; + +error: + snd_card_free(card); + return err; } /* * ALSA destructor From 415927dcd118ee9e5f24c78976509b9a9c747545 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:24 -0300 Subject: [PATCH 210/310] V4L/DVB (6186): cx88-alsa: Remove some unused fields in card state struct Not sure why they are there, but they don't do anything now. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 25de25fb8052..f4abed454fd4 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -53,13 +53,9 @@ Data type declarations - Can be moded to a header file later ****************************************************************************/ -/* These can be replaced after done */ -#define MIXER_ADDR_LAST MAX_CX88_INPUT - struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; - u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -78,9 +74,6 @@ struct cx88_audio_dev { struct videobuf_dmabuf dma_risc; - int mixer_volume[MIXER_ADDR_LAST+1][2]; - int capture_source[MIXER_ADDR_LAST+1][2]; - struct cx88_buffer *buf; struct snd_pcm_substream *substream; From fc959befe0f0e4647bb4e326e3ae55875401888a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 19:08:17 -0300 Subject: [PATCH 211/310] V4L/DVB (6190): cx23885: GPIO fix for non HVR1800lp boards The HVR1250 and HVR1800 boards need the s5h1409 demod GPIO enabled. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 291cc0556222..ffa4c49d6916 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -80,6 +80,15 @@ static struct videobuf_queue_ops dvb_qops = { }; static struct s5h1409_config hauppauge_generic_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -103,7 +112,6 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); @@ -113,6 +121,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_generic_tunerconfig, 0); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); From bfde287c2f8f0fe4e50e0eb136e4dca6b0ed84dc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 15:50:31 -0300 Subject: [PATCH 212/310] V4L/DVB (6191): Removed a redundant switch() The switch() statement is no longer required. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 13dc7c8642ca..f5b73c4b625e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1025,18 +1025,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", - __FUNCTION__); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } + cx_write(port->reg_vld_misc, 0x00); cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); From 661c7e44c5cc2828c7acb00cb71d985e129e3641 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 16:07:49 -0300 Subject: [PATCH 213/310] V4L/DVB (6192): Ensure start_dma() is capable of starting dma on port VIDB start_dma() would fail to start dma if a device used VIDB (portb). Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 9 ++++++--- drivers/media/video/cx23885/cx23885.h | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f5b73c4b625e..907ea4c2ea38 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1015,9 +1015,12 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", - __FUNCTION__, cx23885_boards[dev->board].portc ); + if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && + (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) { + printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n", + __FUNCTION__, + cx23885_boards[dev->board].portb, + cx23885_boards[dev->board].portc ); return -EINVAL; } diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index c0f4e4337351..e44698a6bede 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -86,12 +86,14 @@ struct cx23885_input { u32 gpio0, gpio1, gpio2, gpio3; }; +typedef enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB +} port_t; + struct cx23885_board { char *name; - enum { - CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB - } portc; + port_t portb, portc; struct cx23885_input input[MAX_CX23885_INPUT]; }; From ccbe64c664f2e3a86430ef63c974e38ac1cd5b93 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 11:25:37 -0300 Subject: [PATCH 214/310] V4L/DVB (6193): cx23885: define Video B Interrupt Status register bit values - define missing register bit values for VID_B - corrected VID/VBI_B_GPCNT_CTL register addresses Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-reg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 63ab0fb26acb..3f1afbeea778 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -237,6 +237,13 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_RISCI1 1 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) @@ -344,8 +351,8 @@ Channel manager Data Structure entry = 20 DWORD #define VBI_B_DMA 0x00130108 #define VID_B_GPCNT 0x00130120 #define VBI_B_GPCNT 0x00130124 -#define VID_B_GPCNT_CTL 0x00130130 -#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_GPCNT_CTL 0x00130134 +#define VBI_B_GPCNT_CTL 0x00130138 #define VID_B_DMA_CTL 0x00130140 #define VID_B_SRC_SEL 0x00130144 #define VID_B_LNGTH 0x00130150 From 6f074abb624aced31339a0f8fac778b344adac4c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 14:21:03 -0300 Subject: [PATCH 215/310] V4L/DVB (6194): Changes to support interrupts on VIDB Changes to support interrupts on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 59 ++++++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 907ea4c2ea38..d155f5fb133c 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1252,20 +1252,23 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; u32 pci_status, pci_mask; + u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; int count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); - + ts1_status = cx_read(VID_B_INT_STAT); + ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); ts2_mask = cx_read(VID_C_INT_MSK); - if ( (pci_status == 0) && (ts2_status == 0) ) + if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; count = cx_read(port->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || @@ -1303,6 +1306,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } + if ( (ts1_status & VID_B_MSK_OPC_ERR) || + (ts1_status & VID_B_MSK_BAD_PKT) || + (ts1_status & VID_B_MSK_SYNC) || + (ts1_status & VID_B_MSK_OF)) + { + if (ts1_status & VID_B_MSK_OPC_ERR) + dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); + if (ts1_status & VID_B_MSK_BAD_PKT) + dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); + if (ts1_status & VID_B_MSK_SYNC) + dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); + if (ts1_status & VID_B_MSK_OF) + dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (ts1_status & VID_B_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts1_status & VID_B_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (ts1_status) { + cx_write(VID_B_INT_STAT, ts1_status); + handled = 1; + } + if ( (ts2_status & VID_C_MSK_OPC_ERR) || (ts2_status & VID_C_MSK_BAD_PKT) || (ts2_status & VID_C_MSK_SYNC) || @@ -1341,9 +1386,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - cx_write(VID_C_INT_STAT, ts2_status); - cx_write(PCI_INT_STAT, pci_status); - handled = 1; + if (ts2_status) { + cx_write(VID_C_INT_STAT, ts2_status); + handled = 1; + } + + if (handled) + cx_write(PCI_INT_STAT, pci_status); out: return IRQ_RETVAL(handled); } From 579f1163cd5b2a3fd96ec5b84b18a071e7da3b6b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 15:07:02 -0300 Subject: [PATCH 216/310] V4L/DVB (6195): Changes to support MPEG TS on VIDB Changes to support MPEG TS on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 142 ++++++++++++--------- drivers/media/video/cx23885/cx23885.h | 7 + 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d155f5fb133c..553a72ae163a 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -100,12 +100,12 @@ struct sram_channel cx23885_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "ch3", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10780, + .cdt = 0x10400, + .fifo_start = 0x5000, + .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, @@ -596,7 +596,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); @@ -679,6 +679,39 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) atomic_inc(&dev->refcount); dev->nr = cx23885_devcount++; + sprintf(dev->name, "cx23885[%d]", dev->nr); + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; + dev->sram_channels = cx23887_sram_channels; + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; + } else + BUG(); + + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; @@ -717,38 +750,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) spin_lock_init(&dev->ts2.slock); dev->ts2.dev = dev; dev->ts2.nr = 2; - dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); INIT_LIST_HEAD(&dev->ts2.mpegq.queued); dev->ts2.mpegq.timeout.function = cx23885_timeout; dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; init_timer(&dev->ts2.mpegq.timeout); - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - sprintf(dev->name, "cx23885[%d]", dev->nr); - if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " "subsystem: %04x:%04x\n", @@ -759,46 +767,18 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) goto fail_free; } - mutex_lock(&devlist); - list_add_tail(&dev->devlist, &cx23885_devlist); - mutex_unlock(&devlist); - /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; - /* board config */ - dev->board = UNSET; - if (card[dev->nr] < cx23885_bcount) - dev->board = card[dev->nr]; - for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) - if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && - dev->pci->subsystem_device == cx23885_subids[i].subdevice) - dev->board = cx23885_subids[i].card; - if (UNSET == dev->board) { - dev->board = CX23885_BOARD_UNKNOWN; - cx23885_card_list(dev); - } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device, cx23885_boards[dev->board].name, dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the internal memory */ - if(dev->pci->device == 0x8880) { - dev->bridge = CX23885_BRIDGE_887; - dev->sram_channels = cx23887_sram_channels; - } else - if(dev->pci->device == 0x8852) { - dev->bridge = CX23885_BRIDGE_885; - dev->sram_channels = cx23885_sram_channels; - } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", - __FUNCTION__, dev->bridge); - cx23885_pci_quirks(dev); /* init hardware */ @@ -812,6 +792,38 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); + switch (dev->board) { + default: + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + dev->ts2.reg_src_sel = 0; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH06; + } + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + // FIXME: This should only be called if ts2 is being used, driven by cards.c if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); @@ -1026,13 +1038,17 @@ static int cx23885_start_dma(struct cx23885_tsport *port, udelay(100); + /* If the port supports SRC SELECT, configure it */ + if(port->reg_src_sel) + cx_write(port->reg_src_sel, port->src_sel_val); + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); cx_write(port->reg_vld_misc, 0x00); - cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); + // NOTE: this is 2 (reserved) for portb, does it matter? /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; @@ -1047,7 +1063,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + BUG(); } cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index e44698a6bede..62b44f6d749f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -68,6 +68,11 @@ enum cx23885_itype { CX23885_RADIO, }; +enum cx23885_src_sel_type { + CX23885_SRC_SEL_EXT_656_VIDEO = 0, + CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ @@ -162,6 +167,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_src_sel; /* Default register vals */ int pci_irqmask; @@ -169,6 +175,7 @@ struct cx23885_tsport { u32 ts_int_msk_val; u32 gen_ctrl_val; u32 ts_clk_en_val; + u32 src_sel_val; }; struct cx23885_dev { From 9bc37caadffe8327683980b2323371691fa182e3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 15:17:13 -0300 Subject: [PATCH 217/310] V4L/DVB (6196): cx23885: add support for DViCO FusionHDTV 5 Express This patch adds digital ATSC / QAM support for the DViCO FusionHDTV5 Express. Remote control is supported by ir-kbd-i2c, RTC is supported by rtc-isl1208. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 8 +++++++ drivers/media/video/cx23885/cx23885-core.c | 26 +++++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 18 ++++++++++++++ drivers/media/video/cx23885/cx23885-i2c.c | 6 +++-- drivers/media/video/cx23885/cx23885.h | 1 + drivers/media/video/ir-kbd-i2c.c | 3 +++ drivers/media/video/tuner-core.c | 3 ++- 7 files changed, 62 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 09d4376c2e05..cdda11ddf145 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -109,6 +109,10 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { + .name = "DViCO FusionHDTV5 Express", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -136,6 +140,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7911, .card = CX23885_BOARD_HAUPPAUGE_HVR1250, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd500, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 553a72ae163a..bcba19263476 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -793,6 +793,32 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + dev->ts2.reg_gpcnt = VID_B_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; + dev->ts2.reg_lngth = VID_B_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_B_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_B_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; + dev->ts2.reg_src_sel = VID_B_SRC_SEL; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH03; + break; default: dev->ts2.reg_gpcnt = VID_C_GPCNT; dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index ffa4c49d6916..0ace919195df 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,6 +32,8 @@ #include "s5h1409.h" #include "mt2131.h" +#include "lgdt330x.h" +#include "dvb-pll.h" static unsigned int debug = 0; @@ -101,6 +103,12 @@ static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; +static struct lgdt330x_config fusionhdtv_5_express = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -131,6 +139,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + port->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_5_express, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, port->dvb.frontend, + 0x61, &dev->i2c_bus[0].i2c_adap, + DVB_PLL_LG_TDVS_H06XF); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 5572fbbbb5ae..b517c8b5a566 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -305,12 +305,14 @@ static struct i2c_client cx23885_i2c_client_template = { }; static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt3303", + [ 0x86 >> 1 ] = "tda9887", [ 0x32 >> 1 ] = "cx24227", [ 0x88 >> 1 ] = "cx25837", [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "mt2131/tda8275", - [ 0xc2 >> 1 ] = "mt2131/tda8275", + [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 62b44f6d749f..4933274b1e39 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -54,6 +54,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 +#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 04f6eb5ea292..d98dd0d1e373 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -507,6 +507,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; + static const int probe_cx23885[] = { 0x6b, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; @@ -527,6 +528,8 @@ static int ir_probe(struct i2c_adapter *adap) break; case I2C_HW_B_CX2388x: probe = probe_cx88; + case I2C_HW_B_CX23885: + probe = probe_cx23885; break; } if (NULL == probe) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2d4a3e38f278..94843086cda9 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -665,7 +665,8 @@ static int tuner_probe(struct i2c_adapter *adap) * FusionHDTV5 RT Gold has an ir receiver at 0x6b * and an RTC at 0x6f which can get corrupted if probed. */ - if (adap->id == I2C_HW_B_CX2388x) { + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { unsigned int i = 0; while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) From 15e90839512a2c7d2b7f801af8f9057279e3f813 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 15:58:45 -0300 Subject: [PATCH 218/310] V4L/DVB (6198): add CARDLIST.cx23885 to Documentation/ Cardlist generated by cx23885.pl Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Documentation/video4linux/CARDLIST.cx23885 diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 new file mode 100644 index 000000000000..00cb646a4bde --- /dev/null +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -0,0 +1,5 @@ + 0 -> UNKNOWN/GENERIC [0070:3400] + 1 -> Hauppauge WinTV-HVR1800lp [0070:7600] + 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801] + 3 -> Hauppauge WinTV-HVR1250 [0070:7911] + 4 -> DViCO FusionHDTV5 Express [18ac:d500] From a6a3f14035fe94c0925fea62f3d3a7a1ab44c1f1 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 21:31:56 -0300 Subject: [PATCH 219/310] V4L/DVB (6199): cx23885: Changes to allow demodulators on each transport bus cx23885: Changes to allow demodulators on each transport bus. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 53 +++- drivers/media/video/cx23885/cx23885-core.c | 322 +++++++++----------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +- drivers/media/video/cx23885/cx23885-reg.h | 16 +- drivers/media/video/cx23885/cx23885.h | 5 +- 5 files changed, 206 insertions(+), 194 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index cdda11ddf145..b9012acabb2f 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -111,7 +111,7 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { .name = "DViCO FusionHDTV5 Express", - .portc = CX23885_MPEG_DVB, + .portb = CX23885_MPEG_DVB, }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -197,8 +197,43 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +void cx23885_gpio_setup(struct cx23885_dev *dev) +{ + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + +int cx23885_ir_init(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* FIXME: Implement me */ + break; + } + + return 0; +} + void cx23885_card_setup(struct cx23885_dev *dev) { + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; + static u8 eeprom[256]; if (dev->i2c_bus[0].i2c_rc == 0) { @@ -215,6 +250,22 @@ void cx23885_card_setup(struct cx23885_dev *dev) hauppauge_eeprom(dev, eeprom+0x80); break; } + + switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + default: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + } + } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index bcba19263476..51879961e3ea 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -604,24 +604,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* GPIO-0 cx24227 demodulator reset */ - dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); - cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - /* GPIO-0 656_CLK */ - /* GPIO-1 656_D0 */ - /* GPIO-2 8295A Reset */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - /* GPIO-19 IR_RX */ - dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); - // FIXME: Analog requires the tuner is brought out of reset - break; - } + cx23885_gpio_setup(dev); } @@ -656,17 +639,68 @@ static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); -static int cx23885_ir_init(struct cx23885_dev *dev) +static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno); - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + /* Transport bus init dma queue - Common settings */ + port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + + spin_lock_init(&port->slock); + port->dev = dev; + port->nr = portno; + + INIT_LIST_HEAD(&port->mpegq.active); + INIT_LIST_HEAD(&port->mpegq.queued); + port->mpegq.timeout.function = cx23885_timeout; + port->mpegq.timeout.data = (unsigned long)port; + init_timer(&port->mpegq.timeout); + + switch(portno) { + case 1: + port->reg_gpcnt = VID_B_GPCNT; + port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; + port->reg_dma_ctl = VID_B_DMA_CTL; + port->reg_lngth = VID_B_LNGTH; + port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + port->reg_gen_ctrl = VID_B_GEN_CTL; + port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + port->reg_sop_status = VID_B_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_B_VLD_MISC; + port->reg_ts_clk_en = VID_B_TS_CLK_EN; + port->reg_src_sel = VID_B_SRC_SEL; + port->reg_ts_int_msk = VID_B_INT_MSK; + port->reg_ts_int_stat = VID_B_INT_STAT; + port->sram_chno = SRAM_CH03; /* VID_B */ + port->pci_irqmask = 0x02; /* VID_B bit1 */ break; + case 2: + port->reg_gpcnt = VID_C_GPCNT; + port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; + port->reg_dma_ctl = VID_C_DMA_CTL; + port->reg_lngth = VID_C_LNGTH; + port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + port->reg_gen_ctrl = VID_C_GEN_CTL; + port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + port->reg_sop_status = VID_C_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_C_VLD_MISC; + port->reg_ts_clk_en = VID_C_TS_CLK_EN; + port->reg_src_sel = 0; + port->reg_ts_int_msk = VID_C_INT_MSK; + port->reg_ts_int_stat = VID_C_INT_STAT; + port->sram_chno = SRAM_CH06; /* VID_C */ + port->pci_irqmask = 0x04; /* VID_C bit2 */ + break; + default: + BUG(); } + cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, + port->reg_dma_ctl, port->dma_ctl_val, 0x00); + return 0; } @@ -746,16 +780,11 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ - /* Transport bus init dma queue */ - spin_lock_init(&dev->ts2.slock); - dev->ts2.dev = dev; - dev->ts2.nr = 2; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts1, 1); - INIT_LIST_HEAD(&dev->ts2.mpegq.active); - INIT_LIST_HEAD(&dev->ts2.mpegq.queued); - dev->ts2.mpegq.timeout.function = cx23885_timeout; - dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; - init_timer(&dev->ts2.mpegq.timeout); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts2, 2); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " @@ -788,71 +817,21 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); - cx23885_card_setup(dev); cx23885_ir_init(dev); - switch (dev->board) { - case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: - dev->ts2.reg_gpcnt = VID_B_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; - dev->ts2.reg_lngth = VID_B_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_B_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_B_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; - dev->ts2.reg_src_sel = VID_B_SRC_SEL; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH03; - break; - default: - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - dev->ts2.reg_src_sel = 0; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH06; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts1) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", + __FUNCTION__); + } } - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - // FIXME: This should only be called if ts2 is being used, driven by cards.c - if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", - __FUNCTION__); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", + __FUNCTION__); + } } return 0; @@ -870,7 +849,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; - cx23885_dvb_unregister(&dev->ts2); + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts1); + + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); cx23885_i2c_unregister(&dev->i2c_bus[1]); cx23885_i2c_unregister(&dev->i2c_bus[0]); @@ -1289,14 +1273,66 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } +static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) +{ + struct cx23885_dev *dev = port->dev; + int handled = 0; + u32 count; + + if ( (status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_BAD_PKT) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) + { + if (status & VID_BC_MSK_OPC_ERR) + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); + if (status & VID_BC_MSK_BAD_PKT) + dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT); + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC); + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (status & VID_BC_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (status & VID_BC_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (status) { + cx_write(port->reg_ts_int_stat, status); + handled = 1; + } + + return handled; +} + static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; - struct cx23885_tsport *port = &dev->ts2; + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int count = 0, handled = 0; + int ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); @@ -1308,10 +1344,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; - count = cx_read(port->reg_gpcnt); + ts1_count = cx_read(ts1->reg_gpcnt); + ts2_count = cx_read(ts2->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1348,90 +1385,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if ( (ts1_status & VID_B_MSK_OPC_ERR) || - (ts1_status & VID_B_MSK_BAD_PKT) || - (ts1_status & VID_B_MSK_SYNC) || - (ts1_status & VID_B_MSK_OF)) - { - if (ts1_status & VID_B_MSK_OPC_ERR) - dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); - if (ts1_status & VID_B_MSK_BAD_PKT) - dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); - if (ts1_status & VID_B_MSK_SYNC) - dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); - if (ts1_status & VID_B_MSK_OF) - dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + if (ts1_status) + handled += cx23885_irq_ts(ts1, ts1_status); - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts1_status & VID_B_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts1_status & VID_B_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - if (ts1_status) { - cx_write(VID_B_INT_STAT, ts1_status); - handled = 1; - } - - if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) - { - if (ts2_status & VID_C_MSK_OPC_ERR) - dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); - if (ts2_status & VID_C_MSK_BAD_PKT) - dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); - if (ts2_status & VID_C_MSK_SYNC) - dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); - if (ts2_status & VID_C_MSK_OF) - dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); - - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts2_status & VID_C_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts2_status & VID_C_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - - if (ts2_status) { - cx_write(VID_C_INT_STAT, ts2_status); - handled = 1; - } + if (ts2_status) + handled += cx23885_irq_ts(ts2, ts2_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 0ace919195df..e0dc1495b8cd 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -160,6 +160,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ + /* Assumption here: analog decoder is only on i2c bus 0 */ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ @@ -180,8 +181,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) dev->pci_slot); err = -ENODEV; - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) - goto fail_core; /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); @@ -192,7 +191,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); - fail_core: return err; } diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 3f1afbeea778..162169f9091b 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -250,14 +250,16 @@ Channel manager Data Structure entry = 20 DWORD #define VID_C_MSK_OF (1 << 8) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -#define VID_C_INT_MSK 0x00040040 -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 +/* A superset for testing purposes */ +#define VID_BC_MSK_BAD_PKT (1 << 20) +#define VID_BC_MSK_OPC_ERR (1 << 16) +#define VID_BC_MSK_SYNC (1 << 12) +#define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_RISCI1 1 + +#define VID_C_INT_MSK 0x00040040 #define VID_C_INT_STAT 0x00040044 #define VID_C_INT_MSTAT 0x00040048 #define VID_C_INT_SSTAT 0x0004004C diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4933274b1e39..45c47cd60703 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -168,6 +168,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_ts_int_stat; u32 reg_src_sel; /* Default register vals */ @@ -201,7 +202,7 @@ struct cx23885_dev { unsigned int board; char name[32]; - struct cx23885_tsport ts2; + struct cx23885_tsport ts1, ts2; /* sram configuration */ struct sram_channel *sram_channels; @@ -269,6 +270,8 @@ extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; extern void cx23885_card_list(struct cx23885_dev *dev); +extern int cx23885_ir_init(struct cx23885_dev *dev); +extern void cx23885_gpio_setup(struct cx23885_dev *dev); extern void cx23885_card_setup(struct cx23885_dev *dev); extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); From f139fa71c03d80c1d1ee60aa4b0a3ec7a14d45f9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 03:55:34 -0300 Subject: [PATCH 220/310] V4L/DVB (6200): cx23885: use a pointer to the required i2c bus in dvb_register function Store a pointer to the required i2c_bus so that we do not put the wrong analog demod into standby. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index e0dc1495b8cd..d952f3a67532 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -112,6 +112,7 @@ static struct lgdt330x_config fusionhdtv_5_express = { static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; + struct cx23885_i2c *i2c_bus = NULL; /* init struct videobuf_dvb */ port->dvb.name = dev->name; @@ -120,33 +121,35 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_express, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, port->dvb.frontend, - 0x61, &dev->i2c_bus[0].i2c_adap, - DVB_PLL_LG_TDVS_H06XF); + dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61, + &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; default: @@ -160,8 +163,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ - /* Assumption here: analog decoder is only on i2c bus 0 */ - cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, From 289ea1f03353104c4f288f6c70c5c7e1568ea257 Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Mon, 10 Sep 2007 13:37:26 -0300 Subject: [PATCH 221/310] V4L/DVB (6203): Fix SVideo input on KWorld DVB-T 220 boards Fix SVideo input on KWorld DVB-T 220 boards. Without this patch, the luma pin on the SVideo input is treated as a composite in, and the chroma pin is ignored. Also, fix the radio, and provide a second composite input for people who are used to the existing composite on SVideo connector behaviour. Signed-off-by: Simon Farnsworth Reviewed-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 5c3174a62e58..c4dc9868c48b 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2771,6 +2771,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 1 << 21, .inputs = {{ .name = name_tv, .vmux = 1, @@ -2781,13 +2782,18 @@ struct saa7134_board saa7134_boards[] = { .vmux = 3, .amux = LINE1, },{ - .name = name_svideo, + .name = name_comp2, .vmux = 0, .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, }}, .radio = { .name = name_radio, - .amux = LINE1, + .amux = TV, + .gpio = 0x0200000, }, }, [SAA7134_BOARD_KWORLD_DVBT_210] = { From 747f07961e9450058522840129cd7bb994f05fb9 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:10:11 -0300 Subject: [PATCH 222/310] V4L/DVB (6205): pvrusb2: Fix oops in error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 6bbed88d7867..22719ba861ac 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -33,8 +33,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); - flush_workqueue(mp->workqueue); - destroy_workqueue(mp->workqueue); + if (mp->workqueue) { + flush_workqueue(mp->workqueue); + destroy_workqueue(mp->workqueue); + } kfree(mp); } From 401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:11:46 -0300 Subject: [PATCH 223/310] V4L/DVB (6207): pvrusb2: Fix a potential oops in an error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 2d5be5cfbccf..5d9045268cf5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2172,6 +2172,7 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { + if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); if (hdw->fw_buffer) { kfree(hdw->fw_buffer); From 4db666cc3d199a8b837174bb0ad00d6b8f6115d6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:16:27 -0300 Subject: [PATCH 224/310] V4L/DVB (6208): pvrusb2: Implement programmatic means to extract prom contents The pvrusb2 driver already has a method for extracting the FX2's program memory back out to a user application; this ability is used to facilitate manual firmware extraction as per the procedure documented on the pvrusb2 web site. This change follows that pattern and implements a corresponding method to grab the binary contents of the PVR USB2 prom (which for PVR USB2 devices can contain information in addition to the usual Hauppauge metadata). Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- .../media/video/pvrusb2/pvrusb2-debugifc.c | 16 +- .../video/pvrusb2/pvrusb2-hdw-internal.h | 1 + drivers/media/video/pvrusb2/pvrusb2-hdw.c | 156 ++++++++++++++---- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 12 +- 4 files changed, 150 insertions(+), 35 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index e9da9bb8f8de..6f135f4a2497 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, count -= scnt; buf += scnt; if (!wptr) return -EINVAL; if (debugifc_match_keyword(wptr,wlen,"fetch")) { - pvr2_hdw_cpufw_set_enabled(hdw,!0); + scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); + if (scnt && wptr) { + count -= scnt; buf += scnt; + if (debugifc_match_keyword(wptr,wlen,"prom")) { + pvr2_hdw_cpufw_set_enabled(hdw,!0,!0); + } else if (debugifc_match_keyword(wptr,wlen, + "ram")) { + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); + } else { + return -EINVAL; + } + } + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); return 0; } else if (debugifc_match_keyword(wptr,wlen,"done")) { - pvr2_hdw_cpufw_set_enabled(hdw,0); + pvr2_hdw_cpufw_set_enabled(hdw,0,0); return 0; } else { return -EINVAL; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index ce66ab8ff2d8..985d9ae7f5ee 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -238,6 +238,7 @@ struct pvr2_hdw { // CPU firmware info (used to help find / save firmware data) char *fw_buffer; unsigned int fw_size; + int fw_cpu_flag; /* True if we are dealing with the CPU */ // Which subsystem pieces have been enabled / configured unsigned long subsys_enabled_mask; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 5d9045268cf5..7172f66a6a28 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2605,7 +2605,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) } while (0); LOCK_GIVE(hdw->big_lock); } -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) + +/* Grab EEPROM contents, needed for direct method. */ +#define EEPROM_SIZE 8192 +#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) +static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) +{ + struct i2c_msg msg[2]; + u8 *eeprom; + u8 iadd[2]; + u8 addr; + u16 eepromSize; + unsigned int offs; + int ret; + int mode16 = 0; + unsigned pcnt,tcnt; + eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); + if (!eeprom) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failed to allocate memory" + " required to read eeprom"); + return NULL; + } + + trace_eeprom("Value for eeprom addr from controller was 0x%x", + hdw->eeprom_addr); + addr = hdw->eeprom_addr; + /* Seems that if the high bit is set, then the *real* eeprom + address is shifted right now bit position (noticed this in + newer PVR USB2 hardware) */ + if (addr & 0x80) addr >>= 1; + + /* FX2 documentation states that a 16bit-addressed eeprom is + expected if the I2C address is an odd number (yeah, this is + strange but it's what they do) */ + mode16 = (addr & 1); + eepromSize = (mode16 ? EEPROM_SIZE : 256); + trace_eeprom("Examining %d byte eeprom at location 0x%x" + " using %d bit addressing",eepromSize,addr, + mode16 ? 16 : 8); + + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].len = mode16 ? 2 : 1; + msg[0].buf = iadd; + msg[1].addr = addr; + msg[1].flags = I2C_M_RD; + + /* We have to do the actual eeprom data fetch ourselves, because + (1) we're only fetching part of the eeprom, and (2) if we were + getting the whole thing our I2C driver can't grab it in one + pass - which is what tveeprom is otherwise going to attempt */ + memset(eeprom,0,EEPROM_SIZE); + for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { + pcnt = 16; + if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; + offs = tcnt + (eepromSize - EEPROM_SIZE); + if (mode16) { + iadd[0] = offs >> 8; + iadd[1] = offs; + } else { + iadd[0] = offs; + } + msg[1].len = pcnt; + msg[1].buf = eeprom+tcnt; + if ((ret = i2c_transfer(&hdw->i2c_adap, + msg,ARRAY_SIZE(msg))) != 2) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "eeprom fetch set offs err=%d",ret); + kfree(eeprom); + return NULL; + } + } + return eeprom; +} + + +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, + int prom_flag, + int enable_flag) { int ret; u16 address; @@ -2619,38 +2697,60 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; hdw->fw_size = 0; - /* Now release the CPU. It will disconnect and - reconnect later. */ - pvr2_hdw_cpureset_assert(hdw,0); + if (hdw->fw_cpu_flag) { + /* Now release the CPU. It will disconnect + and reconnect later. */ + pvr2_hdw_cpureset_assert(hdw,0); + } break; } - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Preparing to suck out CPU firmware"); - hdw->fw_size = 0x2000; - hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); - if (!hdw->fw_buffer) { - hdw->fw_size = 0; - break; + hdw->fw_cpu_flag = (prom_flag == 0); + if (hdw->fw_cpu_flag) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Preparing to suck out CPU firmware"); + hdw->fw_size = 0x2000; + hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); + if (!hdw->fw_buffer) { + hdw->fw_size = 0; + break; + } + + /* We have to hold the CPU during firmware upload. */ + pvr2_hdw_cpureset_assert(hdw,1); + + /* download the firmware from address 0000-1fff in 2048 + (=0x800) bytes chunk. */ + + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Grabbing CPU firmware"); + pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); + for(address = 0; address < hdw->fw_size; + address += 0x800) { + ret = usb_control_msg(hdw->usb_dev,pipe, + 0xa0,0xc0, + address,0, + hdw->fw_buffer+address, + 0x800,HZ); + if (ret < 0) break; + } + + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done grabbing CPU firmware"); + } else { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Sucking down EEPROM contents"); + hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); + if (!hdw->fw_buffer) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "EEPROM content suck failed."); + break; + } + hdw->fw_size = EEPROM_SIZE; + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done sucking down EEPROM contents"); } - /* We have to hold the CPU during firmware upload. */ - pvr2_hdw_cpureset_assert(hdw,1); - - /* download the firmware from address 0000-1fff in 2048 - (=0x800) bytes chunk. */ - - pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware"); - pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); - for(address = 0; address < hdw->fw_size; address += 0x800) { - ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0, - address,0, - hdw->fw_buffer+address,0x800,HZ); - if (ret < 0) break; - } - - pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware"); - } while (0); LOCK_GIVE(hdw->big_lock); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 4dba8d006324..e2f9d5e4cb65 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); -/* Enable / disable retrieval of CPU firmware. This must be enabled before - pvr2_hdw_cpufw_get() will function. Note that doing this may prevent - the device from running (and leaving this mode may imply a device - reset). */ -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); +/* Enable / disable retrieval of CPU firmware or prom contents. This must + be enabled before pvr2_hdw_cpufw_get() will function. Note that doing + this may prevent the device from running (and leaving this mode may + imply a device reset). */ +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, + int prom_flag, + int enable_flag); /* Return true if we're in a mode for retrieval CPU firmware */ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); From 1d643a372259749ce2029e386ed5760d5d7f8b89 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:18:50 -0300 Subject: [PATCH 225/310] V4L/DVB (6209): pvrusb2: Better discriminate among device types This is a bunch of cleanup in various places to improve behavior based on actual device type being driven. While this doesn't actually affect operation with existing devices, it cleans things up so that it will be easier / more deterministic when other devices are added. Ideally we should make stuff like this table-driven, but for now this is just a series of small incremental (read: safe) improvements. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 84 +++++++++++++++-------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 7172f66a6a28..c8ee379159e2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1143,6 +1143,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) }, }; + + if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || + (!fw_file_defs[hdw->hdw_type].lst)) { + hdw->fw1_state = FW1_STATE_OK; + return 0; + } + hdw->fw1_state = FW1_STATE_FAILED; // default result trace_firmware("pvr2_upload_firmware1"); @@ -1224,6 +1231,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; + if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && + (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { + return 0; + } + trace_firmware("pvr2_upload_firmware2"); ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", @@ -1742,30 +1754,36 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if (!reloadFl) { - reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints - == 0); + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (!reloadFl) { + reloadFl = + (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints + == 0); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "USB endpoint config looks strange" + "; possibly firmware needs to be" + " loaded"); + } + } + if (!reloadFl) { + reloadFl = !pvr2_hdw_check_firmware(hdw); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "Check for FX2 firmware failed" + "; possibly firmware needs to be" + " loaded"); + } + } if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "USB endpoint config looks strange" - "; possibly firmware needs to be loaded"); + if (pvr2_upload_firmware1(hdw) != 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failure uploading firmware1"); + } + return; } } - if (!reloadFl) { - reloadFl = !pvr2_hdw_check_firmware(hdw); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "Check for FX2 firmware failed" - "; possibly firmware needs to be loaded"); - } - } - if (reloadFl) { - if (pvr2_upload_firmware1(hdw) != 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failure uploading firmware1"); - } - return; - } hdw->fw1_state = FW1_STATE_OK; if (initusbreset) { @@ -1773,17 +1791,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) { - request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]); + if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { + for (idx = 0; + idx < pvr2_client_lists[hdw->hdw_type].cnt; + idx++) { + request_module( + pvr2_client_lists[hdw->hdw_type].lst[idx]); + } } - pvr2_hdw_cmd_powerup(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + pvr2_hdw_cmd_powerup(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; - if (pvr2_upload_firmware2(hdw)){ - pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); - pvr2_hdw_render_useless(hdw); - return; + if (pvr2_upload_firmware2(hdw)){ + pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); + pvr2_hdw_render_useless(hdw); + return; + } } // This step MUST happen after the earlier powerup step. From 9f66d4eac6be2428901ab6e0cbb6747d5b6794ef Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:28:51 -0300 Subject: [PATCH 226/310] V4L/DVB (6210): pvrusb2: Do a far better job at setting the default initial video standard The v4l tveeprom logic tells us what video standards are supported by the hardware, however it doesn't directly tell us what should be the preferred initial standard. For example "NTSC/NTSC-J" devices are reported by tveeprom as support NTSC-M and PAL-M, and while that might be true, in the vast majority of cases NTSC-M is really what the user is going to want. However the driver previously just arbitrarily picked the "lowest numbered" standard as the initial default, which in that case would have been PAL-M. (And making matters more confusing - this only caused real problems on 24xxx devices because the saa7115 on 29xxx seems to autodetect the right answer anyway.) This change implements an algorithm that uses the set of "supported" standards as a hint to decide on the initial standard. This algorithm ONLY comes into play if the driver isn't specifically told what to do; said another way - the user can always still change the standard via the sysfs interface, via the usual V4L methods, or even specified as a module parameter. The idea here is only to pick a better starting point if the user (or app) doesn't otherwise do something to set the standard; otherwise this change has no real impact. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 59 +++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c8ee379159e2..20dc573bc150 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1694,6 +1694,44 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) return result == 0; } +struct pvr2_std_hack { + v4l2_std_id pat; /* Pattern to match */ + v4l2_std_id msk; /* Which bits we care about */ + v4l2_std_id std; /* What additional standards or default to set */ +}; + +/* This data structure labels specific combinations of standards from + tveeprom that we'll try to recognize. If we recognize one, then assume + a specified default standard to use. This is here because tveeprom only + tells us about available standards not the intended default standard (if + any) for the device in question. We guess the default based on what has + been reported as available. Note that this is only for guessing a + default - which can always be overridden explicitly - and if the user + has otherwise named a default then that default will always be used in + place of this table. */ +const static struct pvr2_std_hack std_eeprom_maps[] = { + { /* PAL(B/G) */ + .pat = V4L2_STD_B|V4L2_STD_GH, + .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, + }, + { /* NTSC(M) */ + .pat = V4L2_STD_MN, + .std = V4L2_STD_NTSC_M, + }, + { /* PAL(I) */ + .pat = V4L2_STD_PAL_I, + .std = V4L2_STD_PAL_I, + }, + { /* SECAM(L/L') */ + .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + }, + { /* PAL(D/D1/K) */ + .pat = V4L2_STD_DK, + .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + }, +}; + static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; @@ -1732,6 +1770,27 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) return; } + { + unsigned int idx; + for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { + if (std_eeprom_maps[idx].msk ? + ((std_eeprom_maps[idx].pat ^ + hdw->std_mask_eeprom) & + std_eeprom_maps[idx].msk) : + (std_eeprom_maps[idx].pat != + hdw->std_mask_eeprom)) continue; + bcnt = pvr2_std_id_to_str(buf,sizeof(buf), + std_eeprom_maps[idx].std); + pvr2_trace(PVR2_TRACE_INIT, + "Initial video standard guessed as %.*s", + bcnt,buf); + hdw->std_mask_cur = std_eeprom_maps[idx].std; + hdw->std_dirty = !0; + pvr2_hdw_internal_find_stdenum(hdw); + return; + } + } + if (hdw->std_enum_cnt > 1) { // Autoselect the first listed standard hdw->std_enum_cur = 1; From 56585386e297c54a65feef55810c13b4313bdf1e Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:32:12 -0300 Subject: [PATCH 227/310] V4L/DVB (6211): pvrusb2: Allocate a debug mask bit for reporting video standard things It's useful to see specific details for how the pvrusb2 driver is figuring out things related to the video standard, independent of other initialization activities. So let's set up a separate debug mask bit for this and turn it on. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-debug.h | 53 +++++++++++---------- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 10 ++-- drivers/media/video/pvrusb2/pvrusb2-main.c | 1 + drivers/media/video/pvrusb2/pvrusb2-std.c | 8 ++-- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index d95a8588e4f8..da6441b88f31 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -26,32 +26,33 @@ extern int pvrusb2_debug; /* These are listed in *rough* order of decreasing usefulness and increasing noise level. */ -#define PVR2_TRACE_INFO (1 << 0) // Normal messages -#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages -#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors -#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app -#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps -#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop -#define PVR2_TRACE_CTL (1 << 6) // commit of control changes -#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code -#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report -#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation -#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close -#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit -#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O -#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions -#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation -#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff -#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules -#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging -#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter -#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details -#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation -#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management -#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system -#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow -#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions -#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes +#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */ +#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */ +#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */ +#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */ +#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */ +#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ +#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ +#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ +#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ +#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 20dc573bc150..eec83d6ae788 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1741,7 +1741,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std1 = get_default_standard(hdw); bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Supported video standard(s) reported by eeprom: %.*s", bcnt,buf); @@ -1750,7 +1750,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std2 = std1 & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Expanding supported video standards" " to include: %.*s", bcnt,buf); @@ -1761,7 +1761,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) if (std1) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard forced to %.*s", bcnt,buf); hdw->std_mask_cur = std1; @@ -1781,7 +1781,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_mask_eeprom)) continue; bcnt = pvr2_std_id_to_str(buf,sizeof(buf), std_eeprom_maps[idx].std); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard guessed as %.*s", bcnt,buf); hdw->std_mask_cur = std_eeprom_maps[idx].std; @@ -1796,7 +1796,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_enum_cur = 1; hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id; hdw->std_dirty = !0; - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard auto-selected to %s", hdw->std_defs[hdw->std_enum_cur-1].name); return; diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 1ea0939096ae..ca9e2789c8ca 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -41,6 +41,7 @@ #define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \ PVR2_TRACE_INFO| \ + PVR2_TRACE_STD| \ PVR2_TRACE_TOLERANCE| \ PVR2_TRACE_TRAP| \ 0) diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index 81de26ba41d9..63e55bb59fcb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -298,7 +298,7 @@ static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) std->id = id; bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); std->name[bcnt] = 0; - pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s", + pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s", std->index,std->name); return !0; } @@ -320,11 +320,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, v4l2_std_id idmsk,cmsk,fmsk; struct v4l2_standard *stddefs; - if (pvrusb2_debug & PVR2_TRACE_INIT) { + if (pvrusb2_debug & PVR2_TRACE_STD) { char buf[50]; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); pvr2_trace( - PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)", + PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)", (int)id,bcnt,buf); } @@ -355,7 +355,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt,buf); } - pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)", + pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)", std_cnt); if (!std_cnt) return NULL; // paranoia From 7fb0dfc853735ccf4e580b0d71510bad96d37c4f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Sep 2007 23:19:32 -0300 Subject: [PATCH 228/310] V4L/DVB (6212): pvrusb2: I2C adapter tweaks from Jean Delvare * I2C adapters aren't expected to handle I2C_M_NOSTART unless they really have to. As the pvrusb2 driver doesn't support it, I take it that it doesn't need it so it shouldn't mention it at all. * I2C_FUNC_SMBUS_EMUL includes I2C_FUNC_SMBUS_BYTE_DATA so listing both is redundant. Signed-off-by: Jean Delvare Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 6786d3c0c98b..7697f391e8bb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -389,10 +389,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, ret = -EINVAL; goto done; } - if ((msgs[0].flags & I2C_M_NOSTART)) { - trace_i2c("i2c refusing I2C_M_NOSTART"); - goto done; - } if (msgs[0].addr < PVR2_I2C_FUNC_CNT) { funcp = hdw->i2c_func[msgs[0].addr]; } @@ -494,14 +490,12 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, cnt = msgs[idx].len; printk(KERN_INFO "pvrusb2 i2c xfer %u/%u:" - " addr=0x%x len=%d %s%s", + " addr=0x%x len=%d %s", idx+1,num, msgs[idx].addr, cnt, (msgs[idx].flags & I2C_M_RD ? - "read" : "write"), - (msgs[idx].flags & I2C_M_NOSTART ? - " nostart" : "")); + "read" : "write")); if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { if (cnt > 8) cnt = 8; printk(" ["); @@ -534,7 +528,7 @@ static int pvr2_i2c_control(struct i2c_adapter *adapter, static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static int pvr2_i2c_core_singleton(struct i2c_client *cp, From 39f46adef8e83653b4716369683c134e1413ad30 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 06:17:44 -0300 Subject: [PATCH 229/310] V4L/DVB (6214): usbvision: Don't support I2C_M_REV_DIR_ADDR I2C adapters should only support I2C_M_REV_DIR_ADDR if they really have to (i.e. if they are connected to a broken I2C device which needs this deviation from the standard I2C protocol.) As no media chip driver uses I2C_M_REV_DIR_ADDR, I don't think that the usbvision driver needs to support it. Signed-off-by: Jean Delvare Acked-by: Thierry Merle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-i2c.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 025be555194f..c66aef63916f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -134,8 +134,6 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, addr = (msg->addr << 1); if (flags & I2C_M_RD) addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; add[0] = addr; if (flags & I2C_M_RD) @@ -192,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned static u32 functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } From 588005e1008f2cea61b7a1ae2a86c531e99b8c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans-J=C3=BCrgen=20Koch?= Date: Wed, 12 Sep 2007 16:20:43 -0300 Subject: [PATCH 230/310] V4L/DVB (6215): Bugfix for saa6588.c, add forgotten spin_lock_init() There's a serious bug in saa6588.c, it uses a non-initialized spin_lock. Funny thing is that it works fine with bttv, but completly freezes the machine if e.g. saa7134 is loaded. Thanks to Derek Philip for reporting this bug on the rdsd-devel list. This patch adds the missing spin_lock_init(). Signed-off-by: Hans J. Koch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa6588.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 92eabf88a09b..72e344a12c79 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -406,6 +406,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) kfree(s); return -ENOMEM; } + spin_lock_init(&s->lock); s->client = client_template; s->block_count = 0; s->wr_index = 0; From 098c645e39e10dc580763b5ea4bd4fb390013474 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:38 -0300 Subject: [PATCH 231/310] V4L/DVB (6216): V4L: Int if: add vidioc_int_g_ifparm, other updates vidioc_int_g_ifparm can be used to obtain hardware-specific information about the interface used by the slave. Rearrange v4l2-int-device.h as well. Also remove useless & characters. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 +- include/media/v4l2-int-device.h | 138 +++++++++++++++----------- 2 files changed, 84 insertions(+), 58 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index a643730fa3b2..7ad8700ebdea 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -150,7 +150,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { return ((v4l2_int_ioctl_func_0 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); + (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); } static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) @@ -162,5 +162,5 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { return ((v4l2_int_ioctl_func_1 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); + (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index deb28ce6685d..861978deb3bf 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -30,67 +30,17 @@ #define V4L2NAMESIZE 32 +/* + * + * The internal V4L2 device interface core. + * + */ + enum v4l2_int_type { v4l2_int_type_master = 1, v4l2_int_type_slave }; -enum v4l2_int_ioctl_num { - /* - * - * "Proper" V4L ioctls, as in struct video_device. - * - */ - vidioc_int_enum_fmt_cap_num = 1, - vidioc_int_g_fmt_cap_num, - vidioc_int_s_fmt_cap_num, - vidioc_int_try_fmt_cap_num, - vidioc_int_queryctrl_num, - vidioc_int_g_ctrl_num, - vidioc_int_s_ctrl_num, - vidioc_int_g_parm_num, - vidioc_int_s_parm_num, - - /* - * - * Strictly internal ioctls. - * - */ - /* Initialise the device when slave attaches to the master. */ - vidioc_int_dev_init_num = 1000, - /* Delinitialise the device at slave detach. */ - vidioc_int_dev_exit_num, - /* Set device power state: 0 is off, non-zero is on. */ - vidioc_int_s_power_num, - /* Get parallel interface clock speed for current settings. */ - vidioc_int_g_ext_clk_num, - /* - * Tell what the parallel interface clock speed actually is. - */ - vidioc_int_s_ext_clk_num, - /* Does the slave need to be reset after VIDIOC_DQBUF? */ - vidioc_int_g_needs_reset_num, - - /* - * - * VIDIOC_INT_* ioctls. - * - */ - /* VIDIOC_INT_RESET */ - vidioc_int_reset_num, - /* VIDIOC_INT_INIT */ - vidioc_int_init_num, - /* VIDIOC_INT_G_CHIP_IDENT */ - vidioc_int_g_chip_ident_num, - - /* - * - * Start of private ioctls. - * - */ - vidioc_int_priv_start_num = 2000, -}; - struct v4l2_int_device; struct v4l2_int_master { @@ -141,6 +91,81 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d); int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); +/* + * + * Types and definitions for IOCTL commands. + * + */ + +/* Slave interface type. */ +enum v4l2_if_type { +}; + +struct v4l2_ifparm { + enum v4l2_if_type if_type; + union { + } u; +}; + +/* IOCTL command numbers. */ +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get slave interface parameters. */ + vidioc_int_g_ifparm_num, + /* Get external clock speed for current slave settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the generated interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + /* * * IOCTL wrapper functions for better type checking. @@ -199,6 +224,7 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); From 08256ea0da18db20f2edc2e8c935cf74c33ad564 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:39 -0300 Subject: [PATCH 232/310] V4L/DVB (6217): V4L: Int if: Add BT.656 interface support This patch adds BT.656 interface settings for [gs]_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 861978deb3bf..4e07707bd5ea 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -99,11 +99,61 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); /* Slave interface type. */ enum v4l2_if_type { + /* + * Parallel 8-, 10- or 12-bit interface, used by for example + * on certain image sensors. + */ + V4L2_IF_TYPE_BT656, +}; + +enum v4l2_if_type_bt656_mode { + /* + * Modes without Bt synchronisation codes. Separate + * synchronisation signal lines are used. + */ + V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, + /* + * Use Bt synchronisation codes. The vertical and horizontal + * synchronisation is done based on synchronisation codes. + */ + V4L2_IF_TYPE_BT656_MODE_BT_8BIT, + V4L2_IF_TYPE_BT656_MODE_BT_10BIT, +}; + +struct v4l2_if_type_bt656 { + /* + * 0: Frame begins when vsync is high. + * 1: Frame begins when vsync changes from low to high. + */ + unsigned frame_start_on_rising_vs:1; + /* Use Bt synchronisation codes for sync correction. */ + unsigned bt_sync_correct:1; + /* Swap every two adjacent image data elements. */ + unsigned swap:1; + /* Inverted latch clock polarity from slave. */ + unsigned latch_clk_inv:1; + /* Hs polarity. 0 is active high, 1 active low. */ + unsigned nobt_hs_inv:1; + /* Vs polarity. 0 is active high, 1 active low. */ + unsigned nobt_vs_inv:1; + enum v4l2_if_type_bt656_mode mode; + /* Minimum accepted bus clock for slave (in Hz). */ + u32 clock_min; + /* Maximum accepted bus clock for slave. */ + u32 clock_max; + /* + * Current wish of the slave. May only change in response to + * ioctls that affect image capture. + */ + u32 clock_curr; }; struct v4l2_ifparm { enum v4l2_if_type if_type; union { + struct v4l2_if_type_bt656 bt656; } u; }; From 61c310dc1e2a34bced25b4fa7609316d6755ccc2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:40 -0300 Subject: [PATCH 233/310] V4L/DVB (6218): V4L: Int if: Use -ENOIOCTLCMD for nonexistent ioctls Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7ad8700ebdea..f497c9458344 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -143,7 +143,7 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, static int no_such_ioctl_0(struct v4l2_int_device *d) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) @@ -155,7 +155,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) From 768f4bd3d6a88c13a4099451aa85ae75c9061316 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:41 -0300 Subject: [PATCH 234/310] V4L/DVB (6219): V4L: Int if: Remove [gs]_ext_clk Remove support for g_ext_clk and s_ext_clk. The same functionality is now handled by g_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 4e07707bd5ea..066ebfc4f983 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -187,12 +187,6 @@ enum v4l2_int_ioctl_num { vidioc_int_s_power_num, /* Get slave interface parameters. */ vidioc_int_g_ifparm_num, - /* Get external clock speed for current slave settings. */ - vidioc_int_g_ext_clk_num, - /* - * Tell what the generated interface clock speed actually is. - */ - vidioc_int_s_ext_clk_num, /* Does the slave need to be reset after VIDIOC_DQBUF? */ vidioc_int_g_needs_reset_num, @@ -275,8 +269,6 @@ V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); -V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); -V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); V4L2_INT_WRAPPER_0(reset); From 2060955748dff6280cd211b68c92d9a99d1c78f9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:42 -0300 Subject: [PATCH 235/310] V4L/DVB (6220): TCM825x: Add support for vidioc_int_g_ifparm call, small cleanups vidioc_int_g_ifparm returns platform-specific information about the interface settings used by the sensor. Support for [gs]_ext_clk has been removed. Fix indentation and remove useless & characters. Remove experiment for typechecking slave callback function arguments. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 128 +++++++++++++++------------------- drivers/media/video/tcm825x.h | 4 ++ 2 files changed, 61 insertions(+), 71 deletions(-) diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 3a139f288a9d..41cd6a0b0485 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -470,46 +470,6 @@ static int tcm825x_configure(struct v4l2_int_device *s) return 0; } -/* - * Given the image capture format in pix, the nominal frame period in - * timeperframe, calculate the required xclk frequency. - * - * TCM825X input frequency characteristics are: - * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz - */ -#define XCLK_MIN 11900000 -#define XCLK_MAX 25000000 - -static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_fract *timeperframe = &sensor->timeperframe; - u32 tgt_xclk; /* target xclk */ - u32 tgt_fps; /* target frames per secound */ - - tgt_fps = timeperframe->denominator / timeperframe->numerator; - - tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? - (2457 * tgt_fps) / MAX_HALF_FPS : - (2457 * tgt_fps) / MAX_FPS; - tgt_xclk *= 10000; - - tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); - tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); - - *xclk = tgt_xclk; - - return 0; -} - -static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) -{ - if (xclk > XCLK_MAX || xclk < XCLK_MIN) - return -EINVAL; - - return 0; -} - static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) { @@ -756,6 +716,41 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) return sensor->platform_data->power_set(on); } +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + int rval; + + rval = sensor->platform_data->ifparm(p); + if (rval) + return rval; + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN); + + p->u.bt656.clock_curr = tgt_xclk; + + return 0; +} + static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) { struct tcm825x_sensor *sensor = s->priv; @@ -793,43 +788,39 @@ static int ioctl_dev_init(struct v4l2_int_device *s) return 0; } -#define NUM_IOCTLS 17 - -static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = { { vidioc_int_dev_init_num, - (v4l2_int_ioctl_func *)&ioctl_dev_init }, + (v4l2_int_ioctl_func *)ioctl_dev_init }, { vidioc_int_dev_exit_num, - (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + (v4l2_int_ioctl_func *)ioctl_dev_exit }, { vidioc_int_s_power_num, - (v4l2_int_ioctl_func *)&ioctl_s_power }, - { vidioc_int_g_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, - { vidioc_int_s_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, { vidioc_int_g_needs_reset_num, - (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, { vidioc_int_reset_num, - (v4l2_int_ioctl_func *)&ioctl_reset }, + (v4l2_int_ioctl_func *)ioctl_reset }, { vidioc_int_init_num, - (v4l2_int_ioctl_func *)&ioctl_init }, + (v4l2_int_ioctl_func *)ioctl_init }, { vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, { vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, { vidioc_int_g_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, { vidioc_int_s_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, { vidioc_int_g_parm_num, - (v4l2_int_ioctl_func *)&ioctl_g_parm }, + (v4l2_int_ioctl_func *)ioctl_g_parm }, { vidioc_int_s_parm_num, - (v4l2_int_ioctl_func *)&ioctl_s_parm }, + (v4l2_int_ioctl_func *)ioctl_s_parm }, { vidioc_int_queryctrl_num, - (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + (v4l2_int_ioctl_func *)ioctl_queryctrl }, { vidioc_int_g_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, { vidioc_int_s_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, }; static struct v4l2_int_slave tcm825x_slave = { @@ -894,16 +885,16 @@ static int __exit tcm825x_remove(struct i2c_client *client) } static struct i2c_driver tcm825x_i2c_driver = { - .driver = { + .driver = { .name = TCM825X_NAME, }, - .probe = &tcm825x_probe, - .remove = __exit_p(&tcm825x_remove), + .probe = tcm825x_probe, + .remove = __exit_p(tcm825x_remove), }; static struct tcm825x_sensor tcm825x = { .timeperframe = { - .numerator = 1, + .numerator = 1, .denominator = DEFAULT_FPS, }, }; @@ -911,11 +902,6 @@ static struct tcm825x_sensor tcm825x = { static int __init tcm825x_init(void) { int rval; - int i = 0; - - /* Just an experiment --- don't use *_cb functions yet. */ - tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); - BUG_ON(i >= NUM_IOCTLS); rval = i2c_add_driver(&tcm825x_i2c_driver); if (rval) diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h index d6471ec40bc5..966765b66b3a 100644 --- a/drivers/media/video/tcm825x.h +++ b/drivers/media/video/tcm825x.h @@ -163,6 +163,9 @@ enum pixel_format { YUV422 = 0, RGB565 }; #define NUM_IMAGE_SIZES 6 #define NUM_PIXEL_FORMATS 2 +#define TCM825X_XCLK_MIN 11900000 +#define TCM825X_XCLK_MAX 25000000 + struct capture_size { unsigned long width; unsigned long height; @@ -178,6 +181,7 @@ struct tcm825x_platform_data { const struct tcm825x_reg *(*default_regs)(void); int (*needs_reset)(struct v4l2_int_device *s, void *buf, struct v4l2_pix_format *fmt); + int (*ifparm)(struct v4l2_ifparm *p); }; /* Array of image sizes supported by TCM825X. These must be ordered from From f64899ca5af69c33a446d355609831fad6f715cd Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 17 Sep 2007 22:17:12 -0300 Subject: [PATCH 236/310] V4L/DVB (6221): budget-ci: select TT keymap for DVB-S TT 1500 DVB-S TT 1500 must use the TT keymap. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-ci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 873c3ba296f2..509349211d4f 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x100f: case 0x1011: case 0x1012: - case 0x1017: /* The hauppauge keymap is a superset of these remotes */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_hauppauge_new); @@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: + case 0x1017: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); From c8e2f07be0ac536c110702ed741c7bc6836e3438 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 15 Sep 2007 18:45:10 -0300 Subject: [PATCH 237/310] V4L/DVB (6222): select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express VIDEO_CX23885 must select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 333dd29d44b4..45345fc189e0 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -11,6 +11,7 @@ config VIDEO_CX23885 select VIDEO_BUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. From 0e789d7ffafbfd44f7fb2bdbf1138547d8abc231 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 18 Sep 2007 13:25:45 -0300 Subject: [PATCH 238/310] V4L/DVB (6224): VIDEO_CX23885 depends on DVB_CORE Fix the following dependency issue: ERROR: "dvb_dmx_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_frontend_detach" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_swfilter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "mt2131_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! ERROR: "s5h1409_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 45345fc189e0..ebfcc7c2a89e 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,6 +1,6 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" - depends on VIDEO_DEV && PCI && I2C + depends on DVB_CORE && VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX From f438d97447d4ccd241db8477f62a0647b9e8220e Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 17 Sep 2007 15:34:09 -0300 Subject: [PATCH 239/310] V4L/DVB (6225): AverTV Studio 307 has only one composite input AverTV Studio 307 has only one composite input. Signed-off-by: Stas Sergeev Acked-by: Nickolay V. Shmyrev Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c4dc9868c48b..6b6eae82bcfc 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -32,6 +32,7 @@ static char name_mute[] = "mute"; static char name_radio[] = "Radio"; static char name_tv[] = "Television"; static char name_tv_mono[] = "TV (mono only)"; +static char name_comp[] = "Composite"; static char name_comp1[] = "Composite1"; static char name_comp2[] = "Composite2"; static char name_comp3[] = "Composite3"; @@ -1535,12 +1536,7 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, .gpio = 0x00, },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - .gpio = 0x02, - },{ - .name = name_comp2, + .name = name_comp, .vmux = 3, .amux = LINE1, .gpio = 0x02, From 5d7802b2617d785ea0b8631b0605defc19ee6561 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:03:58 -0300 Subject: [PATCH 240/310] V4L/DVB (6226): dvb-pll: pass fe pointer into dvb_pll_configure() and set() functions The pll-specific set() function will need access to the dvb_pll_priv structure for new functionality. This patch gives access to this structure to the required functions. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 36 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 11f7d5939bd9..59ae4ece65ab 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -29,7 +29,8 @@ struct dvb_pll_desc { u32 min; u32 max; u32 iffreq; - void (*set)(u8 *buf, const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params); u8 *initdata; u8 *sleepdata; int count; @@ -89,7 +90,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }, }; -static void thomson_dtt759x_bw(u8 *buf, +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) @@ -210,7 +211,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -243,7 +245,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) buf[3] |= 0x08; @@ -283,7 +286,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ -static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && params->frequency >= 158870000) @@ -313,7 +317,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x04; @@ -354,7 +359,8 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { /* Philips TUV1236D * used in ATI HDTV Wonder */ -static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params) +static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { switch (params->u.vsb.modulation) { case QAM_64: @@ -420,7 +426,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { /* * Philips TD1316 Tuner. */ -static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void td1316_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { u8 band; @@ -474,7 +481,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = { } }; -static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[2] |= 0x08; @@ -567,9 +575,11 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, +static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { + struct dvb_pll_priv *priv = fe->tuner_priv; + struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; @@ -597,7 +607,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(buf, params); + desc->set(fe, buf, params); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -654,7 +664,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0) + if ((result = dvb_pll_configure(fe, buf, params)) < 0) return result; else frequency = result; @@ -682,7 +692,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0) + if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) return result; else frequency = result; From a27e5e769e46626052fc18ff63f274ee97142bab Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:11:15 -0300 Subject: [PATCH 241/310] V4L/DVB (6227): dvb-pll: store instance ID in dvb_pll_priv structure Store an instance ID in the dvb_pll_priv structure, so that module options specific to a given pll may be used by the functions within the driver. When debug is turned on, print a message indicating which pll was attached and it's instance id. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 59ae4ece65ab..5f4762edc405 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -556,6 +556,9 @@ static struct dvb_pll_desc *pll_list[] = { /* ----------------------------------------------------------- */ struct dvb_pll_priv { + /* pll number */ + int nr; + /* i2c details */ int pll_i2c_address; struct i2c_adapter *i2c; @@ -575,6 +578,8 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); +static unsigned int dvb_pll_devcount; + static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { @@ -787,6 +792,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; + priv->nr = dvb_pll_devcount++; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -801,6 +807,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; + + if (debug) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + } + return fe; } EXPORT_SYMBOL(dvb_pll_attach); From 05a4611b5d71ad6f968fdeef092c24914570898b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:19:57 -0300 Subject: [PATCH 242/310] V4L/DVB (6228): dvb-pll: add module option to specify rf input Add a module option to dvb-pll, called "input" to specify which rf input to use on devices with multiple rf inputs. If the module option is not specified, then the driver will autoselect the rf input, as per previous behavior. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 82 +++++++++++++++++---------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5f4762edc405..7b133248b2bd 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -24,6 +24,36 @@ #include "dvb-pll.h" +struct dvb_pll_priv { + /* pll number */ + int nr; + + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + +#define DVB_PLL_MAX 16 + +static unsigned int dvb_pll_devcount; + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; +module_param_array(input, int, NULL, 0644); +MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); + +/* ----------------------------------------------------------- */ + struct dvb_pll_desc { char *name; u32 min; @@ -362,14 +392,32 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + struct dvb_pll_priv *priv = fe->tuner_priv; + unsigned int new_rf = input[priv->nr]; + + if ((new_rf == 0) || (new_rf > 2)) { + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + new_rf = 1; + break; + case VSB_8: + default: + new_rf = 2; + } + } + + switch (new_rf) { + case 1: buf[3] |= 0x08; break; - case VSB_8: - default: + case 2: buf[3] &= ~0x08; + break; + default: + printk(KERN_WARNING + "%s: unhandled rf input selection: %d", + __FUNCTION__, new_rf); } } @@ -553,33 +601,9 @@ static struct dvb_pll_desc *pll_list[] = { [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d, }; -/* ----------------------------------------------------------- */ - -struct dvb_pll_priv { - /* pll number */ - int nr; - - /* i2c details */ - int pll_i2c_address; - struct i2c_adapter *i2c; - - /* the PLL descriptor */ - struct dvb_pll_desc *pll_desc; - - /* cached frequency/bandwidth */ - u32 frequency; - u32 bandwidth; -}; - /* ----------------------------------------------------------- */ /* code */ -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static unsigned int dvb_pll_devcount; - static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { From ff3e7dd5809fb632447f1aa6de6b3ffb755727dd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 13:00:45 -0300 Subject: [PATCH 243/310] V4L/DVB (6229): dvb-pll: increase DVB_PLL_MAX to 64 Increased DVB_PLL_MAX from 16 to a figure that would never be reached in a practical sense. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 7b133248b2bd..0fb4d453ae5b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -40,7 +40,7 @@ struct dvb_pll_priv { u32 bandwidth; }; -#define DVB_PLL_MAX 16 +#define DVB_PLL_MAX 64 static unsigned int dvb_pll_devcount; From 704e39bf620810734a38b3f9c0e07cede2a76d91 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:27:43 -0300 Subject: [PATCH 244/310] V4L/DVB (6230): dvb-pll: add module option to force dvb-pll desc id (for debug use only) Add a module option to force the dvb-pll module to use an alternate dvb-pll description without having to recompile the kernel. Having a module option like this is useful in some cases, where the vendor may release an alternate revision of the hardware using a different tuner, but without changing the pci subsystem / usb device ids. This option is intended for debugging purposes _only_. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 0fb4d453ae5b..64007032997c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -52,6 +52,11 @@ static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; module_param_array(input, int, NULL, 0644); MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); +static unsigned int id[DVB_PLL_MAX] = + { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; +module_param_array(id, int, NULL, 0644); +MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); + /* ----------------------------------------------------------- */ struct dvb_pll_desc { @@ -794,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, int ret; struct dvb_pll_desc *desc; + if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && + (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) + pll_desc_id = id[dvb_pll_devcount]; + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); desc = pll_list[pll_desc_id]; @@ -836,7 +845,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); - printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + id[priv->nr] == pll_desc_id ? + "insmod option" : "autodetected"); + } return fe; From 8528fa414703f5be17092be2d3a2c5389755253a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:08:30 -0300 Subject: [PATCH 245/310] V4L/DVB (6231): dvb-pll: always show pll name if forced via insmod option The name of the pll will be shown if forced via insmod option, or if debug is enabled. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 64007032997c..27b2d54b6972 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -841,7 +841,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->tuner_priv = priv; - if (debug) { + if ((debug) || (id[priv->nr] == pll_desc_id)) { printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); From 4562fbeac61468f80a8d05e5ed50660bd97b4859 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:16:34 -0300 Subject: [PATCH 246/310] V4L/DVB (6232): dvb-pll: report whether input rf will be autoselected or set via insmod option Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 27b2d54b6972..8c8d7342d0b3 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -848,7 +848,20 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, id[priv->nr] == pll_desc_id ? "insmod option" : "autodetected"); - + } + if ((debug) || (input[priv->nr] > 0)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": tuner rf input will be "); + switch (input[priv->nr]) { + case 0: + printk("autoselected\n"); + break; + default: + printk("set to input %d (insmod option)\n", + input[priv->nr]); + } } return fe; From 23869e236846657415654e8f5fbda9faec8d19e4 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 19 Sep 2007 02:44:18 -0300 Subject: [PATCH 247/310] V4L/DVB (6235): cafe_ccic: default to allocating DMA buffers at probe time By default, we allocate DMA buffers when actually reading from the video capture device. On a system with 128MB or 256MB of ram, it's very easy for that memory to quickly become fragmented. We've had users report having 30+MB of memory free, but the cafe_ccic driver is still unable to allocate DMA buffers. Our workaround has been to make use of the 'alloc_bufs_at_load' parameter to allocate DMA buffers during device probing. This patch makes DMA buffer allocation happen during device probe by default, and changes the parameter to 'alloc_bufs_at_read'. The camera hardware is there, if the cafe_ccic driver is enabled/loaded it should do its best to ensure that the camera is actually usable; delaying DMA buffer allocation saves an insignicant amount of memory, and causes the driver to be much less useful. Signed-off-by: Andres Salomon Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 0fae0e000f1a..ccb37006bb18 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -62,13 +62,13 @@ MODULE_SUPPORTED_DEVICE("Video"); */ #define MAX_DMA_BUFS 3 -static int alloc_bufs_at_load = 0; -module_param(alloc_bufs_at_load, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_load, - "Non-zero value causes DMA buffers to be allocated at module " - "load time. This increases the chances of successfully getting " - "those buffers, but at the cost of nailing down the memory from " - "the outset."); +static int alloc_bufs_at_read = 0; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers."); static int n_dma_bufs = 3; module_param(n_dma_bufs, uint, 0644); @@ -1502,7 +1502,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp) } if (cam->users == 0) { cafe_ctlr_power_down(cam); - if (! alloc_bufs_at_load) + if (alloc_bufs_at_read) cafe_free_dma_bufs(cam); } mutex_unlock(&cam->s_mutex); @@ -2161,7 +2161,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, /* * If so requested, try to get our DMA buffers now. */ - if (alloc_bufs_at_load) { + if (!alloc_bufs_at_read) { if (cafe_alloc_dma_bufs(cam, 1)) cam_warn(cam, "Unable to alloc DMA buffers at load" " will try again later."); From 0b67f5c568c545cb36f88e9f418af2df1cc58589 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 26 Sep 2007 10:19:01 -0300 Subject: [PATCH 248/310] V4L/DVB (6237): Oops in pwc v4l driver The pwc driver is defficient in locking, which can trigger an oops when disconnecting. Signed-off-by: Oliver Neukum CC: Luc Saillard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 96 ++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 1088ebf5744f..0ff5718bf9b9 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -907,31 +907,49 @@ int pwc_isoc_init(struct pwc_device *pdev) return 0; } -void pwc_isoc_cleanup(struct pwc_device *pdev) +static void pwc_iso_stop(struct pwc_device *pdev) { int i; - PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - if (pdev->iso_init == 0) - return; - /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb; urb = pdev->sbuf[i].urb; if (urb != 0) { - if (pdev->iso_init) { - PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); - usb_kill_urb(urb); - } + PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); + usb_kill_urb(urb); + } + } +} + +static void pwc_iso_free(struct pwc_device *pdev) +{ + int i; + + /* Freeing ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { PWC_DEBUG_MEMORY("Freeing URB\n"); usb_free_urb(urb); pdev->sbuf[i].urb = NULL; } } +} + +void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); + if (pdev == NULL) + return; + if (pdev->iso_init == 0) + return; + + pwc_iso_stop(pdev); + pwc_iso_free(pdev); /* Stop camera, but only if we are sure the camera is still there (unplug is signalled by EPIPE) @@ -1211,6 +1229,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + lock_kernel(); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); @@ -1230,7 +1249,6 @@ static int pwc_video_close(struct inode *inode, struct file *file) pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); - lock_kernel(); /* Turn off LEDS and power down camera, but only when not unplugged */ if (!pdev->unplugged) { /* Turn LEDs off */ @@ -1276,7 +1294,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, struct pwc_device *pdev; int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; + int bytes_to_read, rv = 0; void *image_buffer_addr; PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", @@ -1286,8 +1304,12 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, pdev = vdev->priv; if (pdev == NULL) return -EFAULT; - if (pdev->error_status) - return -pdev->error_status; /* Something happened, report what. */ + + mutex_lock(&pdev->modlock); + if (pdev->error_status) { + rv = -pdev->error_status; /* Something happened, report what. */ + goto err_out; + } /* In case we're doing partial reads, we don't have to wait for a frame */ if (pdev->image_read_pos == 0) { @@ -1298,17 +1320,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, if (pdev->error_status) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -pdev->error_status ; + rv = -pdev->error_status ; + goto err_out; } if (noblock) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; + rv = -EWOULDBLOCK; + goto err_out; } if (signal_pending(current)) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -ERESTARTSYS; + rv = -ERESTARTSYS; + goto err_out; } schedule(); set_current_state(TASK_INTERRUPTIBLE); @@ -1317,8 +1342,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, set_current_state(TASK_RUNNING); /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) - return -EFAULT; + if (pwc_handle_frame(pdev)) { + rv = -EFAULT; + goto err_out; + } } PWC_DEBUG_READ("Copying data to user space.\n"); @@ -1333,14 +1360,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, image_buffer_addr = pdev->image_data; image_buffer_addr += pdev->images[pdev->fill_image].offset; image_buffer_addr += pdev->image_read_pos; - if (copy_to_user(buf, image_buffer_addr, count)) - return -EFAULT; + if (copy_to_user(buf, image_buffer_addr, count)) { + rv = -EFAULT; + goto err_out; + } pdev->image_read_pos += count; if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ pdev->image_read_pos = 0; pwc_next_image(pdev); } + mutex_unlock(&pdev->modlock); return count; +err_out: + mutex_unlock(&pdev->modlock); + return rv; } static unsigned int pwc_video_poll(struct file *file, poll_table *wait) @@ -1366,7 +1399,20 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) static int pwc_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int r = -ENODEV; + + if (!vdev) + goto out; + pdev = vdev->priv; + + mutex_lock(&pdev->modlock); + if (!pdev->unplugged) + r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + mutex_unlock(&pdev->modlock); +out: + return r; } static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) @@ -1809,7 +1855,10 @@ static void usb_pwc_disconnect(struct usb_interface *intf) wake_up_interruptible(&pdev->frameq); /* Wait until device is closed */ if(pdev->vopen) { + mutex_lock(&pdev->modlock); pdev->unplugged = 1; + mutex_unlock(&pdev->modlock); + pwc_iso_stop(pdev); } else { /* Device is closed, so we can safely unregister it */ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); @@ -1827,7 +1876,6 @@ disconnect_out: unlock_kernel(); } - /* *grunt* We have to do atoi ourselves :-( */ static int pwc_atoi(const char *s) { From 9e19db5b6dda251b8d76c3a0069e63faca6be3f0 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Fri, 28 Sep 2007 03:19:04 -0300 Subject: [PATCH 249/310] V4L/DVB (6238): bw-qcam: use data_reverse instead of manually poking the control register Fixes use of parport_write_control() to match the newer interface that requires explicit parport_data_reverse() and parport_data_forward() calls. This eliminates the following error message and restores the original intended behavior: parport0 (bw-qcam): use data_reverse for this! Also increases threshold in qc_detect() from 300 to 400, as my camera often results in a count of approx 330. Added a kernel error message to indicate detection failure. Thanks Ray and Randy for your comments, and for pointing out that I needed to reset the port to forward mode! Signed-off-by: Brett T. Warden Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 7d47cbe6ad25..0edd05ebcc3f 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,6 +104,17 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { + if(0x20 & d) { + /* Set bidirectional mode to reverse (data in) */ + parport_data_reverse(q->pport); + } else { + /* Set bidirectional mode to forward (data out) */ + parport_data_forward(q->pport); + } + + /* Now issue the regular port command, but strip out the + * direction flag */ + d &= ~0x20; parport_write_control(q->pport, d); } @@ -344,10 +355,13 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 300) + if (count > 20 && count < 400) + { return 1; /* found */ - else + } else { + printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); return 0; /* not found */ + } } From 0173e4696f201c53ab17ee4d9da81d74b5f9eddc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Sep 2007 11:37:19 -0300 Subject: [PATCH 250/310] V4L/DVB (6241): fix typo in DVB_PLL Kconfig help text s/driver/drives/1 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 53e775539649..59b9ed1f1aec 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -299,7 +299,7 @@ config DVB_PLL depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - This module driver a number of tuners based on PLL chips with a + This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X From 3e7589c50771aa0f6eaa8de799e599c016f4029c Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Sun, 30 Sep 2007 21:49:01 -0300 Subject: [PATCH 251/310] V4L/DVB (6243): [PATCH 2/2] GemTek Radio card Details now match with radio-gemtek.c, eg. no more different ports. Included a short note about cards that should be compatible with radio-gemtek module. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index f8bf9fe37d36..11e962f1a97f 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT jumper sets the card to 0x358. config RADIO_GEMTEK - tristate "GemTek Radio Card support" + tristate "GemTek Radio card (or compatible) support" depends on ISA && VIDEO_V4L2 ---help--- Choose Y here if you have this FM radio card, and then fill in the - port address below. + I/O port address and settings below. The following cards either have + GemTek Radio tuner or are rebranded GemTek Radio cards: + + - Sound Vision 16 Gold with FM Radio + - Typhoon Radio card (some models) + - Hama Radio card In order to control your radio card, you will need to use programs that are compatible with the Video For Linux API. Information on @@ -126,14 +131,25 @@ config RADIO_GEMTEK module will be called radio-gemtek. config RADIO_GEMTEK_PORT - hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)" + hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" depends on RADIO_GEMTEK=y default "34c" help Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is 0x34c, if you haven't changed the jumper setting on the card. On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x28c. + port is 0x20c, 0x248 or 0x28c. + If automatic I/O port probing is enabled this port will be used only + in case of automatic probing failure, ie. as a fallback. + +config RADIO_GEMTEK_PROBE + bool "Automatic I/O port probing" + depends on RADIO_GEMTEK=y + default y + help + Say Y here to enable automatic probing for GemTek Radio card. The + following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and + 0x28c. config RADIO_GEMTEK_PCI tristate "GemTek PCI Radio Card support" From 4753647e6422341a091e729b9d81a9a5e7fe6179 Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Mon, 1 Oct 2007 00:27:55 -0300 Subject: [PATCH 252/310] V4L/DVB (6244): [PATCH 1/2] GemTek Radio card Code cleanup for GemTek Radio card driver. Removed unnecessary / invalid I/O commands and rewrote code for tuning on-board BU2614FS chip. Adds several new module params for power users. Includes automatic device probing. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 661 ++++++++++++++++++++--------- 1 file changed, 467 insertions(+), 194 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index eab8c80a2e47..f959bb71c460 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -26,143 +26,413 @@ #include #include -#include /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +#include /* for KERNEL_VERSION MACRO */ +#define RADIO_VERSION KERNEL_VERSION(0,0,3) +#define RADIO_BANNER "GemTek Radio card driver: v0.0.3" -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +/* + * Module info. + */ + +MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); +MODULE_DESCRIPTION("A driver for the GemTek Radio card."); +MODULE_LICENSE("GPL"); + +/* + * Module params. + */ #ifndef CONFIG_RADIO_GEMTEK_PORT #define CONFIG_RADIO_GEMTEK_PORT -1 #endif +#ifndef CONFIG_RADIO_GEMTEK_PROBE +#define CONFIG_RADIO_GEMTEK_PROBE 1 +#endif -static int io = CONFIG_RADIO_GEMTEK_PORT; -static int radio_nr = -1; -static spinlock_t lock; +static int io = CONFIG_RADIO_GEMTEK_PORT; +static int probe = CONFIG_RADIO_GEMTEK_PROBE; +static int hardmute; +static int shutdown = 1; +static int keepmuted = 1; +static int initmute = 1; +static int radio_nr = -1; -struct gemtek_device -{ - int port; - unsigned long curfreq; +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" + "probing is disabled or fails. The most common I/O ports are: 0x20c " + "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " + " work for the combined sound/radiocard)."); + +module_param(probe, bool, 0444); +MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " + "common I/O ports used by the card are probed."); + +module_param(hardmute, bool, 0644); +MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " + "reduce static noise."); + +module_param(shutdown, bool, 0644); +MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " + "module is unloaded."); + +module_param(keepmuted, bool, 0644); +MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); + +module_param(initmute, bool, 0444); +MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); + +module_param(radio_nr, int, 0444); + +/* + * Functions for controlling the card. + */ +#define GEMTEK_LOWFREQ (87*16000) +#define GEMTEK_HIGHFREQ (108*16000) + +#define GEMTEK_CK 0x01 /* Clock signal */ +#define GEMTEK_DA 0x02 /* Serial data */ +#define GEMTEK_CE 0x04 /* Chip enable */ +#define GEMTEK_NS 0x08 /* No signal */ +#define GEMTEK_MT 0x10 /* Line mute */ +#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */ +#define GEMTEK_PLL_OFF 0x07 /* PLL off */ + +#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ +#define BU2614_NOPS 8 /* Number of supported operations */ + +#define SHORT_DELAY 5 /* usec */ +#define LONG_DELAY 75 /* usec */ + +struct gemtek_device { + unsigned long lastfreq; int muted; + unsigned long bu2614data[BU2614_NOPS]; }; +enum { + BU2614_VOID, + BU2614_FREQ, /* D0..D15, Frequency data */ + BU2614_PORT, /* P0..P2, Output port control data */ + BU2614_FMES, /* CT, Frequency measurement beginning data */ + BU2614_STDF, /* R0..R2, Standard frequency data */ + BU2614_SWIN, /* S, Switch between FMIN / AMIN */ + BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ + BU2614_FMUN, /* GT, Frequency measurement time and unlock */ + BU2614_TEST /* TS, Test data is input */ +}; -/* local things */ +struct bu2614_op { + int op; /* Operation */ + int size; /* Data size */ +}; -/* the correct way to mute the gemtek may be to write the last written - * frequency || 0x10, but just writing 0x10 once seems to do it as well +static struct gemtek_device gemtek_unit; + +static struct bu2614_op bu2614ops[] = { + {.op = BU2614_FREQ, + .size = 0x10}, + {.op = BU2614_PORT, + .size = 0x03}, + {.op = BU2614_VOID, + .size = 0x04}, + {.op = BU2614_FMES, + .size = 0x01}, + {.op = BU2614_STDF, + .size = 0x03}, + {.op = BU2614_SWIN, + .size = 0x01}, + {.op = BU2614_SWAL, + .size = 0x01}, + {.op = BU2614_VOID, + .size = 0x01}, + {.op = BU2614_FMUN, + .size = 0x01}, + {.op = BU2614_TEST, + .size = 0x01} +}; + +static spinlock_t lock; + +/* + * Set data which will be sent to BU2614FS. + */ +static void gemtek_bu2614_set(struct gemtek_device *dev, int op, + unsigned long data) +{ + int i, q; + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + if (bu2614ops[i].op == op) { + dev->bu2614data[q] = + data & ((1 << bu2614ops[i].size) - 1); + return; + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } +} + +/* + * Transmit settings to BU2614FS over GemTek IC. + */ +static void gemtek_bu2614_transmit(struct gemtek_device *dev) +{ + int i, bit, q, mute; + + spin_lock(&lock); + + mute = dev->muted ? GEMTEK_MT : 0x00; + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + for (bit = 0; bit < bu2614ops[i].size; ++bit) { + if (bu2614ops[i].op != BU2614_VOID && + dev->bu2614data[q] & (1 << bit)) { + outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | + GEMTEK_CK, io); + udelay(SHORT_DELAY); + } else { + outb_p(mute | GEMTEK_CE, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); + udelay(SHORT_DELAY); + } + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + + spin_unlock(&lock); +} + +/* + * Convert FM-frequency for BU2614FS (3.125 KHz STDF expected). + */ +static inline void gemtek_convfreq(unsigned long *freq) +{ + (*freq) /= 160; + (*freq) += 1052; /* FMIN, 10.52 MHz */ + (*freq) *= 1565; /* STDF, 1 / 156.5 = 0.00639 */ + (*freq) /= 1000; +} + +/* + * Set FM-frequency. + */ +static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +{ + + if (keepmuted && hardmute && dev->muted) + return; + + if (freq < GEMTEK_LOWFREQ) + freq = GEMTEK_LOWFREQ; + else if (freq > GEMTEK_HIGHFREQ) + freq = GEMTEK_HIGHFREQ; + + dev->lastfreq = freq; + dev->muted = 0; + + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + + gemtek_convfreq(&freq); + + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(dev, BU2614_FREQ, freq); + + gemtek_bu2614_transmit(dev); +} + +/* + * Set mute flag. */ static void gemtek_mute(struct gemtek_device *dev) { - if(dev->muted) - return; - spin_lock(&lock); - outb(0x10, io); - spin_unlock(&lock); + int i; dev->muted = 1; + + if (hardmute) { + /* Turn off PLL, disable data output */ + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */ + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(dev, BU2614_FREQ, 0); + gemtek_bu2614_transmit(dev); + } else { + spin_lock(&lock); + + /* Read bus contents (CE, CK and DA). */ + i = inb_p(io); + /* Write it back with mute flag set. */ + outb_p((i >> 5) | GEMTEK_MT, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } +/* + * Unset mute flag. + */ static void gemtek_unmute(struct gemtek_device *dev) { - if(dev->muted == 0) - return; - spin_lock(&lock); - outb(0x20, io); - spin_unlock(&lock); + int i; dev->muted = 0; + + if (hardmute) { + /* Turn PLL back on. */ + gemtek_setfreq(dev, dev->lastfreq); + } else { + spin_lock(&lock); + + i = inb_p(io); + outb_p(i >> 5, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } -static void zero(void) +/* + * Get signal strength (= stereo status). + */ +static inline int gemtek_getsigstr(void) { - outb_p(0x04, io); - udelay(5); - outb_p(0x05, io); - udelay(5); + return inb_p(io) & GEMTEK_NS ? 0 : 1; } -static void one(void) +/* + * Check if requested card acts like GemTek Radio card. + */ +static int gemtek_verify(int port) { - outb_p(0x06, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + static int verified = -1; + int i, q; + + if (verified == port) + return 1; + + spin_lock(&lock); + + q = inb_p(port); /* Read bus contents before probing. */ + /* Try to turn on CE, CK and DA respectively and check if card responds + properly. */ + for (i = 0; i < 3; ++i) { + outb_p(1 << i, port); + udelay(SHORT_DELAY); + + if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { + spin_unlock(&lock); + return 0; + } + } + outb_p(q >> 5, port); /* Write bus contents back. */ + udelay(SHORT_DELAY); + + spin_unlock(&lock); + verified = port; + + return 1; } -static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +/* + * Automatic probing for card. + */ +static int gemtek_probe(void) { + int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; int i; -/* freq = 78.25*((float)freq/16000.0 + 10.52); */ + if (!probe) { + printk(KERN_INFO "Automatic device probing disabled.\n"); + return -1; + } - freq /= 16; - freq += 10520; - freq *= 7825; - freq /= 100000; + printk(KERN_INFO "Automatic device probing enabled.\n"); - spin_lock(&lock); + for (i = 0; i < ARRAY_SIZE(ioports); ++i) { + printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]); - /* 2 start bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + if (!request_region(ioports[i], 1, "gemtek-probe")) { + printk(KERN_WARNING "I/O port 0x%x busy!\n", + ioports[i]); + continue; + } - /* 28 frequency bits (lsb first) */ - for (i = 0; i < 14; i++) - if (freq & (1 << i)) - one(); - else - zero(); - /* 36 unknown bits */ - for (i = 0; i < 11; i++) - zero(); - one(); - for (i = 0; i < 4; i++) - zero(); - one(); - zero(); + if (gemtek_verify(ioports[i])) { + printk(KERN_INFO "Card found from I/O port " + "0x%x!\n", ioports[i]); - /* 2 end bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + release_region(ioports[i], 1); - spin_unlock(&lock); + io = ioports[i]; + return io; + } - return 0; + release_region(ioports[i], 1); + } + + printk(KERN_ERR "Automatic probing failed!\n"); + + return -1; } -static int gemtek_getsigstr(struct gemtek_device *dev) -{ - spin_lock(&lock); - inb(io); - udelay(5); - spin_unlock(&lock); - if (inb(io) & 8) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} +/* + * Video 4 Linux stuff. + */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +static struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535, + .default_value = 0xff, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +static struct file_operations gemtek_fops = { + .owner = THIS_MODULE, + .open = video_exclusive_open, + .release = video_exclusive_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) { strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); @@ -172,28 +442,29 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; - if (v->index > 0) return -EINVAL; strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*gemtek_getsigstr(rt); + v->rangelow = GEMTEK_LOWFREQ; + v->rangehigh = GEMTEK_HIGHFREQ; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->signal = 0xffff * gemtek_getsigstr(); + if (v->signal) { + v->audmode = V4L2_TUNER_MODE_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + } else { + v->audmode = V4L2_TUNER_MODE_MONO; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + } + return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { if (v->index > 0) return -EINVAL; @@ -201,38 +472,35 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; - rt->curfreq = f->frequency; - /* needs to be called twice in order for getsigstr to work */ - gemtek_setfreq(rt, rt->curfreq); - gemtek_setfreq(rt, rt->curfreq); + gemtek_setfreq(rt, f->frequency); + return 0; } static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; + f->frequency = rt->lastfreq; return 0; } static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) + struct v4l2_queryctrl *qc) { int i; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -240,7 +508,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, } static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -260,7 +528,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -282,8 +550,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index > 1) return -EINVAL; @@ -306,99 +573,105 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index != 0) return -EINVAL; return 0; } -static struct gemtek_device gemtek_unit; - -static const struct file_operations gemtek_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, +static struct video_device gemtek_radio = { + .owner = THIS_MODULE, + .name = "GemTek Radio card", + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_GEMTEK, + .fops = &gemtek_fops, + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl }; -static struct video_device gemtek_radio= -{ - .owner = THIS_MODULE, - .name = "GemTek radio", - .type = VID_TYPE_TUNER, - .fops = &gemtek_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; +/* + * Initialization / cleanup related stuff. + */ +/* + * Initilize card. + */ static int __init gemtek_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n"); - return -EINVAL; - } + int i; - if (!request_region(io, 4, "gemtek")) - { - printk(KERN_ERR "gemtek: port 0x%x already in use\n", io); - return -EBUSY; - } - - gemtek_radio.priv=&gemtek_unit; - - if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { - release_region(io, 4); - return -EINVAL; - } - printk(KERN_INFO "GemTek Radio Card driver.\n"); + printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); - /* this is _maybe_ unnecessary */ - outb(0x01, io); + gemtek_probe(); + if (io) { + if (!request_region(io, 1, "gemtek")) { + printk(KERN_ERR "I/O port 0x%x already in use.\n", io); + return -EBUSY; + } - /* mute card - prevents noisy bootups */ - gemtek_unit.muted = 0; - gemtek_mute(&gemtek_unit); + if (!gemtek_verify(io)) + printk(KERN_WARNING "Card at I/O port 0x%x does not " + "respond properly, check your " + "configuration.\n", io); + else + printk(KERN_INFO "Using I/O port 0x%x.\n", io); + } else if (probe) { + printk(KERN_ERR "Automatic probing failed and no " + "fixed I/O port defined.\n"); + return -ENODEV; + } else { + printk(KERN_ERR "Automatic probing disabled but no fixed " + "I/O port defined."); + return -EINVAL; + } + + gemtek_radio.priv = &gemtek_unit; + + if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, + radio_nr) == -1) { + release_region(io, 1); + return -EBUSY; + } + + /* Set defaults */ + gemtek_unit.lastfreq = GEMTEK_LOWFREQ; + for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) + gemtek_unit.bu2614data[i] = 0; + + if (initmute) + gemtek_mute(&gemtek_unit); return 0; } -MODULE_AUTHOR("Jonas Munsin"); -MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); -module_param(radio_nr, int, 0); - -static void __exit gemtek_cleanup(void) +/* + * Module cleanup + */ +static void __exit gemtek_exit(void) { + if (shutdown) { + hardmute = 1; /* Turn off PLL */ + gemtek_mute(&gemtek_unit); + } else { + printk(KERN_INFO "Module unloaded but card not muted!\n"); + } + video_unregister_device(&gemtek_radio); - release_region(io,4); + release_region(io, 1); } module_init(gemtek_init); -module_exit(gemtek_cleanup); - -/* - Local variables: - compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" - End: -*/ +module_exit(gemtek_exit); From 857e594ad5662349d95ad33f987cbf55cc356a90 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 1 Oct 2007 00:32:25 -0300 Subject: [PATCH 253/310] V4L/DVB (6245): GemTek Radio card - frequency calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frequency calculation to use better math. It's still the same IF offset and step size (which are not the same as the datasheet says) as the code was before. It's just more efficient and accurate. Signed-off-by: Trent Piepho Reviewed-by: Pekka Seppänen Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index f959bb71c460..0fcd2b09218d 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -89,6 +89,14 @@ module_param(radio_nr, int, 0444); #define GEMTEK_LOWFREQ (87*16000) #define GEMTEK_HIGHFREQ (108*16000) +/* + * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal + * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). + */ +#define FSCALE 8 +#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1< Date: Mon, 1 Oct 2007 00:38:30 -0300 Subject: [PATCH 254/310] V4L/DVB (6246): GemTek Radio card - Control Word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Redoes the way the control word is stored and set. The existing code was a lot more complicated than it needed to be. Signed-off-by: Trent Piepho Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Pekka Seppänen --- drivers/media/radio/radio-gemtek.c | 122 ++++++++++------------------- 1 file changed, 43 insertions(+), 79 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 0fcd2b09218d..0c963db03614 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -106,7 +106,6 @@ module_param(radio_nr, int, 0444); #define GEMTEK_PLL_OFF 0x07 /* PLL off */ #define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ -#define BU2614_NOPS 8 /* Number of supported operations */ #define SHORT_DELAY 5 /* usec */ #define LONG_DELAY 75 /* usec */ @@ -114,72 +113,53 @@ module_param(radio_nr, int, 0444); struct gemtek_device { unsigned long lastfreq; int muted; - unsigned long bu2614data[BU2614_NOPS]; + u32 bu2614data; }; -enum { - BU2614_VOID, - BU2614_FREQ, /* D0..D15, Frequency data */ - BU2614_PORT, /* P0..P2, Output port control data */ - BU2614_FMES, /* CT, Frequency measurement beginning data */ - BU2614_STDF, /* R0..R2, Standard frequency data */ - BU2614_SWIN, /* S, Switch between FMIN / AMIN */ - BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ - BU2614_FMUN, /* GT, Frequency measurement time and unlock */ - BU2614_TEST /* TS, Test data is input */ -}; +#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ +#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ +#define BU2614_VOID_BITS 4 /* unused */ +#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */ +#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */ +#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */ +#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/ +#define BU2614_VOID2_BITS 1 /* unused */ +#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */ +#define BU2614_TEST_BITS 1 /* TS, Test data is input */ -struct bu2614_op { - int op; /* Operation */ - int size; /* Data size */ -}; +#define BU2614_FREQ_SHIFT 0 +#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT) +#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT) +#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT) +#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT) +#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT) +#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT) +#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT) +#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT) +#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT) + +#define MKMASK(field) (((1<bu2614data); ++i) { - if (bu2614ops[i].op == op) { - dev->bu2614data[q] = - data & ((1 << bu2614ops[i].size) - 1); - return; - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; - } -} +#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \ + ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) /* * Transmit settings to BU2614FS over GemTek IC. @@ -197,25 +177,12 @@ static void gemtek_bu2614_transmit(struct gemtek_device *dev) outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); udelay(LONG_DELAY); - for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { - for (bit = 0; bit < bu2614ops[i].size; ++bit) { - if (bu2614ops[i].op != BU2614_VOID && - dev->bu2614data[q] & (1 << bit)) { - outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | - GEMTEK_CK, io); - udelay(SHORT_DELAY); - } else { - outb_p(mute | GEMTEK_CE, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); - udelay(SHORT_DELAY); - } - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; + for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; + outb_p(mute | GEMTEK_CE | bit, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io); + udelay(SHORT_DELAY); } outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); @@ -612,8 +579,6 @@ static struct video_device gemtek_radio = { */ static int __init gemtek_init(void) { - int i; - printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); @@ -651,8 +616,7 @@ static int __init gemtek_init(void) /* Set defaults */ gemtek_unit.lastfreq = GEMTEK_LOWFREQ; - for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) - gemtek_unit.bu2614data[i] = 0; + gemtek_unit.bu2614data = 0; if (initmute) gemtek_mute(&gemtek_unit); From 13595a51c0da8ec212ba6f5df79519dbd74166c0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 1 Oct 2007 08:51:39 -0300 Subject: [PATCH 255/310] V4L/DVB (6247): Fix bug #8689: Fixes IR stop/start during suspend/resume IR workqueue should be disabled during suspend. This avoids some troubles, like the one reported on bug #8689: "The Hauppauge HVR 1100 ir-remote control does not work after resume from suspend to ram or disk." This patch disables IR before suspending, re-enabling it after resume. Thanks to Peter Poklop for reporting it and helping with the fix. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Peter Poklop --- drivers/media/video/cx88/cx88-core.c | 3 +++ drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 6 ++++++ drivers/media/video/cx88/cx88.h | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 41f7f374c183..716154828ff0 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1084,6 +1084,9 @@ EXPORT_SYMBOL(cx88_vdev_init); EXPORT_SYMBOL(cx88_core_get); EXPORT_SYMBOL(cx88_core_put); +EXPORT_SYMBOL(cx88_ir_start); +EXPORT_SYMBOL(cx88_ir_stop); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 78adf4d1cf63..e52de3968c63 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -158,7 +158,7 @@ static void cx88_ir_work(struct work_struct *work) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { setup_timer(&ir->timer, ir_timer, (unsigned long)ir); @@ -172,7 +172,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) } } -static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f94a3b41782a..705c29b002ea 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1954,6 +1954,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); + if (core->ir) + cx88_ir_stop(core, core->ir); /* FIXME -- shutdown device */ cx88_shutdown(core); @@ -1993,6 +1995,10 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* FIXME: re-initialize hardware */ cx88_reset(core); + if (core->ir) + cx88_ir_start(core, core->ir); + + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e436a37b4404..0e4f8e278671 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -614,6 +614,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); int cx88_ir_fini(struct cx88_core *core); void cx88_ir_irq(struct cx88_core *core); +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir); +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir); /* ----------------------------------------------------------- */ /* cx88-mpeg.c */ From b5457b7bdf284d683880163a4c59fdde2f84325a Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Tue, 2 Oct 2007 12:23:39 -0300 Subject: [PATCH 256/310] V4L/DVB (6249): Add Typhoon Tv-Tuner PCI to bttv-cards.c Adds an entry for the Typhoon Tv-Tuner PCI to bttv-cards.c Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.bttv | 1 + drivers/media/video/bt8xx/bttv-cards.c | 17 +++++++++++++++++ drivers/media/video/bt8xx/bttv.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 177159c5f4c4..d97cf7cc6088 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -147,3 +147,4 @@ 146 -> SSAI Ultrasound Video Interface [414a:5353] 147 -> VoodooTV 200 (USA) [121a:3000] 148 -> DViCO FusionHDTV 2 [dbc0:d200] +149 -> Typhoon TV-Tuner PCI (50684) diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 900d18e14060..dd6a7d68b07f 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -2988,6 +2988,23 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, }, + /* ---- card 0x95---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { + .name = "Typhoon TV-Tuner PCI (50684)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = { 2, 3, 1, 1 }, + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index dcc847dc2486..19e75d50a107 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -172,6 +172,8 @@ #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 #define BTTV_BOARD_VOODOOTV_200 0x93 #define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 +#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 + /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 From 7c596fa964806acb3b5ababb7ec4e1da35b140b3 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Tue, 2 Oct 2007 17:37:21 -0300 Subject: [PATCH 257/310] V4L/DVB (6250): bw-qcam use data_reverse instead of manually poking the control register fix coding-style repairs Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 0edd05ebcc3f..7f7e3d3398d0 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,7 +104,7 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { - if(0x20 & d) { + if (d & 0x20) { /* Set bidirectional mode to reverse (data in) */ parport_data_reverse(q->pport); } else { @@ -355,11 +355,11 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 400) - { + if (count > 20 && count < 400) { return 1; /* found */ } else { - printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); + printk(KERN_ERR "No Quickcam found on port %s\n", + q->pport->name); return 0; /* not found */ } } From 7a7d9a89d0307b1743d782197e2c5fc5ddf183f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:26:14 -0300 Subject: [PATCH 258/310] V4L/DVB (6251): Replace video-buf to a more generic approach video-buf currently does two different tasks: - Manages video buffers with a common code that allows implementing all the V4L2 different modes of buffering; - Controls memory allocations While the first task is generic, the second were written to support PCI DMA Scatter/Gather needs. The original approach can't even work for those video capture hardware that don't support scatter/gather. I did one approach to make it more generic. While the approach worked fine for vivi driver, it were not generic enough to handle USB needs. This patch creates two different modules, one containing the generic video buffer handling (videobuf-core) and another with PCI DMA S/G. After this patch, it would be simpler to write an USB video-buf and a non-SG DMA module. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 976 ++++++++++++++++++++++++++ drivers/media/video/videobuf-dma-sg.c | 772 ++++++++++++++++++++ include/media/videobuf-core.h | 236 +++++++ include/media/videobuf-dma-sg.h | 142 ++++ 4 files changed, 2126 insertions(+) create mode 100644 drivers/media/video/videobuf-core.c create mode 100644 drivers/media/video/videobuf-dma-sg.c create mode 100644 include/media/videobuf-core.h create mode 100644 include/media/videobuf-dma-sg.h diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c new file mode 100644 index 000000000000..256501384af7 --- /dev/null +++ b/drivers/media/video/videobuf-core.c @@ -0,0 +1,976 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_BUFFER 0x20070728 +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +#define CALL(q, f, arg...) \ + ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + +void* videobuf_alloc(struct videobuf_queue* q) +{ + struct videobuf_buffer *vb; + + BUG_ON (q->msizeint_ops || !q->int_ops->alloc) { + printk(KERN_ERR "No specific ops defined!\n"); + BUG(); + } + + vb = q->int_ops->alloc(q->msize); + + if (NULL != vb) { + init_waitqueue_head(&vb->done); + vb->magic = MAGIC_BUFFER; + } + + return vb; +} + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) +{ + int retval = 0; + DECLARE_WAITQUEUE(wait, current); + + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + add_wait_queue(&vb->done, &wait); + while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + if (non_blocking) { + retval = -EAGAIN; + break; + } + set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); + if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + schedule(); + set_current_state(TASK_RUNNING); + if (intr && signal_pending(current)) { + dprintk(1,"buffer waiton: -EINTR\n"); + retval = -EINTR; + break; + } + } + remove_wait_queue(&vb->done, &wait); + return retval; +} + +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + return CALL(q,iolock,q,vb,fbuf); +} + +/* --------------------------------------------------------------------- */ + + +void videobuf_queue_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + memset(q,0,sizeof(*q)); + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; + q->priv_data = priv; + + /* All buffer operations are mandatory */ + BUG_ON (!q->ops->buf_setup); + BUG_ON (!q->ops->buf_prepare); + BUG_ON (!q->ops->buf_queue); + BUG_ON (!q->ops->buf_release); + + mutex_init(&q->lock); + INIT_LIST_HEAD(&q->stream); +} + +int videobuf_queue_is_busy(struct videobuf_queue *q) +{ + int i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + if (q->streaming) { + dprintk(1,"busy: streaming active\n"); + return 1; + } + if (q->reading) { + dprintk(1,"busy: pending read #1\n"); + return 1; + } + if (q->read_buf) { + dprintk(1,"busy: pending read #2\n"); + return 1; + } + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (CALL(q,is_mmapped,q->bufs[i])) { + dprintk(1,"busy: buffer #%d mapped\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_QUEUED) { + dprintk(1,"busy: buffer #%d queued\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_ACTIVE) { + dprintk(1,"busy: buffer #%d avtive\n",i); + return 1; + } + } + return 0; +} + +void videobuf_queue_cancel(struct videobuf_queue *q) +{ + unsigned long flags=0; + int i; + + /* remove queued buffers from list */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (q->bufs[i]->state == STATE_QUEUED) { + list_del(&q->bufs[i]->queue); + q->bufs[i]->state = STATE_ERROR; + } + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + /* free all buffers + clear queue */ + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + } + INIT_LIST_HEAD(&q->stream); +} + +/* --------------------------------------------------------------------- */ + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q) +{ + enum v4l2_field field = q->field; + + BUG_ON(V4L2_FIELD_ANY == field); + + if (V4L2_FIELD_ALTERNATE == field) { + if (V4L2_FIELD_TOP == q->last) { + field = V4L2_FIELD_BOTTOM; + q->last = V4L2_FIELD_BOTTOM; + } else { + field = V4L2_FIELD_TOP; + q->last = V4L2_FIELD_TOP; + } + } + return field; +} + +static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, + struct videobuf_buffer *vb, enum v4l2_buf_type type) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + b->index = vb->i; + b->type = type; + + b->memory = vb->memory; + switch (b->memory) { + case V4L2_MEMORY_MMAP: + b->m.offset = vb->boff; + b->length = vb->bsize; + break; + case V4L2_MEMORY_USERPTR: + b->m.userptr = vb->baddr; + b->length = vb->bsize; + break; + case V4L2_MEMORY_OVERLAY: + b->m.offset = vb->boff; + break; + } + + b->flags = 0; + if (CALL(q,is_mmapped,vb)) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + switch (vb->state) { + case STATE_PREPARED: + case STATE_QUEUED: + case STATE_ACTIVE: + b->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case STATE_DONE: + case STATE_ERROR: + b->flags |= V4L2_BUF_FLAG_DONE; + break; + case STATE_NEEDS_INIT: + case STATE_IDLE: + /* nothing */ + break; + } + + if (vb->input != UNSET) { + b->flags |= V4L2_BUF_FLAG_INPUT; + b->input = vb->input; + } + + b->field = vb->field; + b->timestamp = vb->ts; + b->bytesused = vb->size; + b->sequence = vb->field_count >> 1; +} + +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req) +{ + unsigned int size,count; + int retval; + + if (req->type != q->type) { + dprintk(1,"reqbufs: queue type invalid\n"); + return -EINVAL; + } + if (req->count < 1) { + dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + return -EINVAL; + } + if (req->memory != V4L2_MEMORY_MMAP && + req->memory != V4L2_MEMORY_USERPTR && + req->memory != V4L2_MEMORY_OVERLAY) { + dprintk(1,"reqbufs: memory type invalid\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1,"reqbufs: streaming already exists\n"); + return -EBUSY; + } + if (!list_empty(&q->stream)) { + dprintk(1,"reqbufs: stream running\n"); + return -EBUSY; + } + + mutex_lock(&q->lock); + count = req->count; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = 0; + q->ops->buf_setup(q,&count,&size); + size = PAGE_ALIGN(size); + dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + count, size, (count*size)>>PAGE_SHIFT); + + retval = videobuf_mmap_setup(q,count,size,req->memory); + if (retval < 0) { + dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + goto done; + } + + req->count = count; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) +{ + if (unlikely(b->type != q->type)) { + dprintk(1,"querybuf: Wrong type.\n"); + return -EINVAL; + } + if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + dprintk(1,"querybuf: index out of range.\n"); + return -EINVAL; + } + if (unlikely(NULL == q->bufs[b->index])) { + dprintk(1,"querybuf: buffer is null.\n"); + return -EINVAL; + } + videobuf_status(q,b,q->bufs[b->index],q->type); + return 0; +} + +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b) +{ + struct videobuf_buffer *buf; + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"qbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"qbuf: Wrong type.\n"); + goto done; + } + if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + dprintk(1,"qbuf: index out of range.\n"); + goto done; + } + buf = q->bufs[b->index]; + if (NULL == buf) { + dprintk(1,"qbuf: buffer is null.\n"); + goto done; + } + MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + if (buf->memory != b->memory) { + dprintk(1,"qbuf: memory type is wrong.\n"); + goto done; + } + if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + dprintk(1,"qbuf: buffer is already queued or active.\n"); + goto done; + } + + if (b->flags & V4L2_BUF_FLAG_INPUT) { + if (b->input >= q->inputs) { + dprintk(1,"qbuf: wrong input.\n"); + goto done; + } + buf->input = b->input; + } else { + buf->input = UNSET; + } + + switch (b->memory) { + case V4L2_MEMORY_MMAP: + if (0 == buf->baddr) { + dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + goto done; + } + break; + case V4L2_MEMORY_USERPTR: + if (b->length < buf->bsize) { + dprintk(1,"qbuf: buffer length is not enough\n"); + goto done; + } + if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + q->ops->buf_release(q,buf); + buf->baddr = b->m.userptr; + break; + case V4L2_MEMORY_OVERLAY: + buf->boff = b->m.offset; + break; + default: + dprintk(1,"qbuf: wrong memory type\n"); + goto done; + } + + dprintk(1,"qbuf: requesting next field\n"); + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,buf,field); + if (0 != retval) { + dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + goto done; + } + + list_add_tail(&buf->stream,&q->stream); + if (q->streaming) { + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + } + dprintk(1,"qbuf: succeded\n"); + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking) +{ + struct videobuf_buffer *buf; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"dqbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"dqbuf: Wrong type.\n"); + goto done; + } + if (list_empty(&q->stream)) { + dprintk(1,"dqbuf: stream running\n"); + goto done; + } + buf = list_entry(q->stream.next, struct videobuf_buffer, stream); + retval = videobuf_waiton(buf, nonblocking, 1); + if (retval < 0) { + dprintk(1,"dqbuf: waiton returned %d\n",retval); + goto done; + } + switch (buf->state) { + case STATE_ERROR: + dprintk(1,"dqbuf: state is error\n"); + retval = -EIO; + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + case STATE_DONE: + dprintk(1,"dqbuf: state is done\n"); + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + default: + dprintk(1,"dqbuf: state invalid\n"); + retval = -EINVAL; + goto done; + } + list_del(&buf->stream); + memset(b,0,sizeof(*b)); + videobuf_status(q,b,buf,q->type); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamon(struct videobuf_queue *q) +{ + struct videobuf_buffer *buf; + struct list_head *list; + unsigned long flags=0; + int retval; + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) + goto done; + retval = 0; + if (q->streaming) + goto done; + q->streaming = 1; + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + list_for_each(list,&q->stream) { + buf = list_entry(list, struct videobuf_buffer, stream); + if (buf->state == STATE_PREPARED) + q->ops->buf_queue(q,buf); + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamoff(struct videobuf_queue *q) +{ + int retval = -EINVAL; + + mutex_lock(&q->lock); + if (!q->streaming) + goto done; + videobuf_queue_cancel(q); + q->streaming = 0; + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, + char __user *data, + size_t count, loff_t *ppos) +{ + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + /* setup stuff */ + q->read_buf = videobuf_alloc(q); + if (NULL == q->read_buf) + return -ENOMEM; + + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->baddr = (unsigned long)data; + q->read_buf->bsize = count; + + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + if (0 != retval) + goto done; + + /* start capture & wait */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + retval = videobuf_waiton(q->read_buf,0,0); + if (0 == retval) { + CALL(q,sync,q,q->read_buf); + if (STATE_ERROR == q->read_buf->state) + retval = -EIO; + else + retval = q->read_buf->size; + } + + done: + /* cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + return retval; +} + +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking) +{ + enum v4l2_field field; + unsigned long flags=0; + unsigned size, nbufs; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + + nbufs = 1; size = 0; + q->ops->buf_setup(q,&nbufs,&size); + + if (NULL == q->read_buf && + count >= size && + !nonblocking) { + retval = videobuf_read_zerocopy(q,data,count,ppos); + if (retval >= 0 || retval == -EIO) + /* ok, all done */ + goto done; + /* fallback to kernel bounce buffer on failures */ + } + + if (NULL == q->read_buf) { + /* need to capture a new frame */ + retval = -ENOMEM; + q->read_buf = videobuf_alloc(q); + + dprintk(1,"video alloc=0x%p\n", q->read_buf); + if (NULL == q->read_buf) + goto done; + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->bsize = count; /* preferred size */ + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + + if (0 != retval) { + kfree (q->read_buf); + q->read_buf = NULL; + goto done; + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_off = 0; + } + + /* wait until capture is done */ + retval = videobuf_waiton(q->read_buf, nonblocking, 1); + if (0 != retval) + goto done; + + CALL(q,sync,q,q->read_buf); + + if (STATE_ERROR == q->read_buf->state) { + /* catch I/O errors */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + retval = -EIO; + goto done; + } + + /* Copy to userspace */ + retval=CALL(q,copy_to_user,q,data,count,nonblocking); + if (retval<0) + goto done; + + q->read_off += retval; + if (q->read_off == q->read_buf->size) { + /* all data copied, cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_read_start(struct videobuf_queue *q) +{ + enum v4l2_field field; + unsigned long flags=0; + int count = 0, size = 0; + int err, i; + + q->ops->buf_setup(q,&count,&size); + if (count < 2) + count = 2; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = PAGE_ALIGN(size); + + err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); + if (err) + return err; + + for (i = 0; i < count; i++) { + field = videobuf_next_field(q); + err = q->ops->buf_prepare(q,q->bufs[i],field); + if (err) + return err; + list_add_tail(&q->bufs[i]->stream, &q->stream); + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < count; i++) + q->ops->buf_queue(q,q->bufs[i]); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->reading = 1; + return 0; +} + +void videobuf_read_stop(struct videobuf_queue *q) +{ + int i; + + videobuf_queue_cancel(q); + videobuf_mmap_free(q); + INIT_LIST_HEAD(&q->stream); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + q->read_buf = NULL; + q->reading = 0; +} + +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking) +{ + int rc, retval; + unsigned long flags=0; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + dprintk(2,"%s\n",__FUNCTION__); + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->streaming) + goto done; + if (!q->reading) { + retval = videobuf_read_start(q); + if (retval < 0) + goto done; + } + + retval = 0; + while (count > 0) { + /* get / wait for data */ + if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + rc = videobuf_waiton(q->read_buf, nonblocking, 1); + if (rc < 0) { + if (0 == retval) + retval = rc; + break; + } + + if (q->read_buf->state == STATE_DONE) { + rc = CALL (q,copy_stream, q, data, count, + retval, vbihack, nonblocking); + if (rc < 0) { + retval = rc; + break; + } + retval += rc; + count -= rc; + q->read_off += rc; + } else { + /* some error */ + q->read_off = q->read_buf->size; + if (0 == retval) + retval = -EIO; + } + + /* requeue buffer when done with copying */ + if (q->read_off == q->read_buf->size) { + list_add_tail(&q->read_buf->stream, + &q->stream); + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_buf = NULL; + } + if (retval < 0) + break; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait) +{ + struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; + + mutex_lock(&q->lock); + if (q->streaming) { + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, + struct videobuf_buffer, stream); + } else { + if (!q->reading) + videobuf_read_start(q); + if (!q->reading) { + rc = POLLERR; + } else if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + buf = q->read_buf; + } + if (!buf) + rc = POLLERR; + + if (0 == rc) { + poll_wait(file, &buf->done, wait); + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) + rc = POLLIN|POLLRDNORM; + } + mutex_unlock(&q->lock); + return rc; +} + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + unsigned int i; + int err; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + err = videobuf_mmap_free(q); + if (0 != err) + return err; + + /* Allocate and initialize buffers */ + for (i = 0; i < bcount; i++) { + q->bufs[i] = videobuf_alloc(q); + + q->bufs[i]->i = i; + q->bufs[i]->input = UNSET; + q->bufs[i]->memory = memory; + q->bufs[i]->bsize = bsize; + switch (memory) { + case V4L2_MEMORY_MMAP: + q->bufs[i]->boff = bsize * i; + break; + case V4L2_MEMORY_USERPTR: + case V4L2_MEMORY_OVERLAY: + /* nothing */ + break; + } + } + + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + bcount,bsize); + + return 0; +} + +int videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + int rc; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + rc = CALL(q,mmap_free,q); + if (rc<0) + return rc; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + return rc; +} + +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval=CALL(q,mmap_mapper,q,vma); + mutex_unlock(&q->lock); + + return retval; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count) +{ + struct v4l2_requestbuffers req; + int rc,i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = count; + req.memory = V4L2_MEMORY_MMAP; + rc = videobuf_reqbufs(q,&req); + if (rc < 0) + return rc; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_waiton); +EXPORT_SYMBOL_GPL(videobuf_iolock); + +EXPORT_SYMBOL_GPL(videobuf_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_cancel); +EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); + +EXPORT_SYMBOL_GPL(videobuf_next_field); +EXPORT_SYMBOL_GPL(videobuf_reqbufs); +EXPORT_SYMBOL_GPL(videobuf_querybuf); +EXPORT_SYMBOL_GPL(videobuf_qbuf); +EXPORT_SYMBOL_GPL(videobuf_dqbuf); +EXPORT_SYMBOL_GPL(videobuf_cgmbuf); +EXPORT_SYMBOL_GPL(videobuf_streamon); +EXPORT_SYMBOL_GPL(videobuf_streamoff); + +EXPORT_SYMBOL_GPL(videobuf_read_start); +EXPORT_SYMBOL_GPL(videobuf_read_stop); +EXPORT_SYMBOL_GPL(videobuf_read_stream); +EXPORT_SYMBOL_GPL(videobuf_read_one); +EXPORT_SYMBOL_GPL(videobuf_poll_stream); + +EXPORT_SYMBOL_GPL(videobuf_mmap_setup); +EXPORT_SYMBOL_GPL(videobuf_mmap_free); +EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c new file mode 100644 index 000000000000..3345877c47d4 --- /dev/null +++ b/drivers/media/video/videobuf-dma-sg.c @@ -0,0 +1,772 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x19721112 +#define MAGIC_SG_MEM 0x17890714 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +struct scatterlist* +videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) +{ + struct scatterlist *sglist; + struct page *pg; + int i; + + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { + pg = vmalloc_to_page(virt); + if (NULL == pg) + goto err; + BUG_ON(PageHighMem(pg)); + sglist[i].page = pg; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + err: + kfree(sglist); + return NULL; +} + +struct scatterlist* +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) +{ + struct scatterlist *sglist; + int i = 0; + + if (NULL == pages[0]) + return NULL; + sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + + if (NULL == pages[0]) + goto nopage; + if (PageHighMem(pages[0])) + /* DMA to highmem pages might not work */ + goto highmem; + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) + goto nopage; + if (PageHighMem(pages[i])) + goto highmem; + sglist[i].page = pages[i]; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + nopage: + dprintk(2,"sgl: oops - no page\n"); + kfree(sglist); + return NULL; + + highmem: + dprintk(2,"sgl: oops - highmem page\n"); + kfree(sglist); + return NULL; +} + +/* --------------------------------------------------------------------- */ + +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return &mem->dma; +} + +void videobuf_dma_init(struct videobuf_dmabuf *dma) +{ + memset(dma,0,sizeof(*dma)); + dma->magic = MAGIC_DMABUF; +} + +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + unsigned long first,last; + int err, rw = 0; + + dma->direction = direction; + switch (dma->direction) { + case PCI_DMA_FROMDEVICE: rw = READ; break; + case PCI_DMA_TODEVICE: rw = WRITE; break; + default: BUG(); + } + + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma->offset = data & ~PAGE_MASK; + dma->nr_pages = last-first+1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", + data,size,dma->nr_pages); + + dma->varea = (void *) data; + + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data & PAGE_MASK, dma->nr_pages, + rw == READ, 1, /* force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { + dma->nr_pages = (err >= 0) ? err : 0; + dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + return err < 0 ? err : -EINVAL; + } + return 0; +} + +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages) +{ + dprintk(1,"init kernel [%d pages]\n",nr_pages); + dma->direction = direction; + dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == dma->vmalloc) { + dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); + return -ENOMEM; + } + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)dma->vmalloc, + nr_pages << PAGE_SHIFT); + memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages) +{ + dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", + nr_pages,(unsigned long)addr); + dma->direction = direction; + if (0 == addr) + return -EINVAL; + + dma->bus_addr = addr; + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(0 == dma->nr_pages); + + if (dma->pages) { + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); + } + if (dma->vmalloc) { + dma->sglist = videobuf_vmalloc_to_sg + (dma->vmalloc,dma->nr_pages); + } + if (dma->bus_addr) { + dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + if (NULL != dma->sglist) { + dma->sglen = 1; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; + sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; + } + } + if (NULL == dma->sglist) { + dprintk(1,"scatterlist is NULL\n"); + return -ENOMEM; + } + if (!dma->bus_addr) { + if (ops && ops->vb_map_sg) { + dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->nr_pages, dma->direction); + } + if (0 == dma->sglen) { + printk(KERN_WARNING + "%s: videobuf_map_sg failed\n",__FUNCTION__); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return -EIO; + } + } + return 0; +} + +int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(!dma->sglen); + + if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + + return 0; +} + +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + if (!dma->sglen) + return 0; + + if (!dma->bus_addr && ops && ops->vb_unmap_sg) + ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return 0; +} + +int videobuf_dma_free(struct videobuf_dmabuf *dma) +{ + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(dma->sglen); + + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; + } + + vfree(dma->vmalloc); + dma->vmalloc = NULL; + dma->varea = NULL; + + if (dma->bus_addr) { + dma->bus_addr = 0; + } + dma->direction = PCI_DMA_NONE; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_map(&q,dma)); +} + +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_unmap(&q,dma)); +} + +/* --------------------------------------------------------------------- */ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_pci_sg_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +/* + * Get a anonymous page for the mapping. Make sure we can DMA to that + * memory location with 32bit PCI devices (i.e. don't use highmem for + * now ...). Bounce buffers don't work very well for the data rates + * video capture has. + */ +static struct page* +videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, + int *type) +{ + struct page *page; + + dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", + vaddr,vma->vm_start,vma->vm_end); + if (vaddr > vma->vm_end) + return NOPAGE_SIGBUS; + page = alloc_page(GFP_USER | __GFP_DMA32); + if (!page) + return NOPAGE_OOM; + clear_user_page(page_address(page), vaddr, page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .nopage = videobuf_vm_nopage, +}; + +/* --------------------------------------------------------------------- + * PCI handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_SG_MEM; + + videobuf_dma_init(&mem->dma); + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int err,pages; + dma_addr_t bus; + struct videbuf_pci_sg_memory *mem=vb->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + if (0 == vb->baddr) { + /* no userspace addr -- kernel bounce buffer */ + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_kernel( &mem->dma, + PCI_DMA_FROMDEVICE, + pages ); + if (0 != err) + return err; + } else { + /* dma directly to userspace */ + err = videobuf_dma_init_user( &mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr,vb->bsize ); + if (0 != err) + return err; + } + break; + case V4L2_MEMORY_OVERLAY: + if (NULL == fbuf) + return -EINVAL; + /* FIXME: need sanity checks for vb->boff */ + /* + * Using a double cast to avoid compiler warnings when + * building for PAE. Compiler doesn't like direct casting + * of a 32 bit ptr to 64 bit integer. + */ + bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE, + bus, pages); + if (0 != err) + return err; + break; + default: + BUG(); + } + err = videobuf_dma_map(q,&mem->dma); + if (0 != err) + return err; + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return videobuf_dma_sync(q,&mem->dma); +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_mapping *map; + unsigned int first,last,size,i; + int retval; + + retval = -EINVAL; + if (!(vma->vm_flags & VM_WRITE)) { + dprintk(1,"mmap app bug: PROT_WRITE please\n"); + goto done; + } + if (!(vma->vm_flags & VM_SHARED)) { + dprintk(1,"mmap app bug: MAP_SHARED please\n"); + goto done; + } + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + goto done; + } + + /* look for last buffer to map */ + for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { + if (NULL == q->bufs[last]) + continue; + if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) + continue; + mem=q->bufs[last]->priv; + if (mem->map) { + retval = -EBUSY; + goto done; + } + size += q->bufs[last]->bsize; + if (size == (vma->vm_end - vma->vm_start)) + break; + } + if (VIDEO_MAX_FRAME == last) { + dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", + (vma->vm_end - vma->vm_start)); + goto done; + } + + /* create mapping + update buffer list */ + retval = -ENOMEM; + map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + goto done; + for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { + mem=q->bufs[i]->priv; + mem->map = map; + q->bufs[i]->baddr = vma->vm_start + size; + } + map->count = 1; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + vma->vm_private_data = map; + dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", + map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); + retval = 0; + + done: + return retval; +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->dma.vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops pci_ops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void *videobuf_pci_alloc (size_t size) +{ + struct videobuf_queue q; + + /* Required to make generic handler to call __videobuf_alloc */ + q.int_ops=&pci_ops; + + q.msize=size; + + return videobuf_alloc (&q); +} + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + struct videobuf_dma_sg_ops *priv_ops; + + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&pci_ops; + + /* FIXME: the code bellow should be removed after having a proper + * memory allocation method for vivi and tm6000 + */ + q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); + BUG_ON (!q->priv_ops); + + priv_ops=q->priv_ops; + + /* Sets default methods for handling Scatter Gather mapping */ + priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; +} + +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops) +{ + kfree (q->priv_ops); + + q->priv_ops=ops; + + if (!ops) + return; + + /* If not specified, defaults to PCI map sg */ + if (!ops->vb_map_sg) + ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + + if (!ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; + if (!ops->vb_unmap_sg) + ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; +} + + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); + +EXPORT_SYMBOL_GPL(videobuf_to_dma); +EXPORT_SYMBOL_GPL(videobuf_dma_init); +EXPORT_SYMBOL_GPL(videobuf_dma_init_user); +EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); +EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); +EXPORT_SYMBOL_GPL(videobuf_dma_map); +EXPORT_SYMBOL_GPL(videobuf_dma_sync); +EXPORT_SYMBOL_GPL(videobuf_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_dma_free); + +EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); +EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_pci_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); +EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h new file mode 100644 index 000000000000..0ac21ae44f69 --- /dev/null +++ b/include/media/videobuf-core.h @@ -0,0 +1,236 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#ifdef CONFIG_VIDEO_V4L1_COMPAT +#include +#endif +#include + +#define UNSET (-1U) + + +struct videobuf_buffer; +struct videobuf_queue; + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage video4linux buffers. + * + * struct videobuf_buffer holds the data structures used by the helper + * functions, additionally some commonly used fields for v4l buffers + * (width, height, lists, waitqueue) are in there. That struct should + * be used as first element in the drivers buffer struct. + * + * about the mmap helpers (videobuf_mmap_*): + * + * The mmaper function allows to map any subset of contingous buffers. + * This includes one mmap() call for all buffers (which the original + * video4linux API uses) as well as one mmap() for every single buffer + * (which v4l2 uses). + * + * If there is a valid mapping for a buffer, buffer->baddr/bsize holds + * userspace address + size which can be feeded into the + * videobuf_dma_init_user function listed above. + * + */ + +struct videobuf_mapping { + unsigned int count; + unsigned long start; + unsigned long end; + struct videobuf_queue *q; +}; + +enum videobuf_state { + STATE_NEEDS_INIT = 0, + STATE_PREPARED = 1, + STATE_QUEUED = 2, + STATE_ACTIVE = 3, + STATE_DONE = 4, + STATE_ERROR = 5, + STATE_IDLE = 6, +}; + +struct videobuf_buffer { + unsigned int i; + u32 magic; + + /* info about the buffer */ + unsigned int width; + unsigned int height; + unsigned int bytesperline; /* use only if != 0 */ + unsigned long size; + unsigned int input; + enum v4l2_field field; + enum videobuf_state state; + struct list_head stream; /* QBUF/DQBUF list */ + + /* touched by irq handler */ + struct list_head queue; + wait_queue_head_t done; + unsigned int field_count; + struct timeval ts; + + /* Memory type */ + enum v4l2_memory memory; + + /* buffer size */ + size_t bsize; + + /* buffer offset (mmap + overlay) */ + size_t boff; + + /* buffer addr (userland ptr!) */ + unsigned long baddr; + + /* Private pointer to allow specific methods to store their data */ + int privsize; + void *priv; +}; + +struct videobuf_queue_ops { + int (*buf_setup)(struct videobuf_queue *q, + unsigned int *count, unsigned int *size); + int (*buf_prepare)(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field); + void (*buf_queue)(struct videobuf_queue *q, + struct videobuf_buffer *vb); + void (*buf_release)(struct videobuf_queue *q, + struct videobuf_buffer *vb); +}; + +#define MAGIC_QTYPE_OPS 0x12261003 + +/* Helper operations - device type dependent */ +struct videobuf_qtype_ops { + u32 magic; + + void* (*alloc) (size_t size); + int (*iolock) (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + int (*mmap) (struct videobuf_queue *q, + unsigned int *count, + unsigned int *size, + enum v4l2_memory memory); + int (*sync) (struct videobuf_queue* q, + struct videobuf_buffer *buf); + int (*copy_to_user) (struct videobuf_queue *q, + char __user *data, + size_t count, + int nonblocking); + int (*copy_stream) (struct videobuf_queue *q, + char __user *data, + size_t count, + size_t pos, + int vbihack, + int nonblocking); + int (*mmap_free) (struct videobuf_queue *q); + int (*mmap_mapper) (struct videobuf_queue *q, + struct vm_area_struct *vma); + int (*is_mmapped) (struct videobuf_buffer *buf); +}; + +struct videobuf_queue { + struct mutex lock; + spinlock_t *irqlock; + void *dev; /* on pci, points to struct pci_dev */ + + enum v4l2_buf_type type; + unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ + unsigned int msize; + enum v4l2_field field; + enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ + struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; + struct videobuf_queue_ops *ops; + struct videobuf_qtype_ops *int_ops; + + /* capture via mmap() + ioctl(QBUF/DQBUF) */ + unsigned int streaming; + struct list_head stream; + + /* capture via read() */ + unsigned int reading; + unsigned int read_off; + struct videobuf_buffer *read_buf; + + /* driver private data */ + void *priv_data; + + /*FIXME: should be removed after completing the vb conversion */ + void *priv_ops; +}; + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + +void *videobuf_alloc(struct videobuf_queue* q); + +void videobuf_queue_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); +int videobuf_queue_is_busy(struct videobuf_queue *q); +void videobuf_queue_cancel(struct videobuf_queue *q); + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q); +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req); +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b); +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking); +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count); +#endif +int videobuf_streamon(struct videobuf_queue *q); +int videobuf_streamoff(struct videobuf_queue *q); + +int videobuf_read_start(struct videobuf_queue *q); +void videobuf_read_stop(struct videobuf_queue *q); +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking); +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking); +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait); + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory); +int videobuf_mmap_free(struct videobuf_queue *q); +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma); + +/* --------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h new file mode 100644 index 000000000000..62a3709905f3 --- /dev/null +++ b/include/media/videobuf-dma-sg.h @@ -0,0 +1,142 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include + +/* --------------------------------------------------------------------- */ + +/* + * Return a scatterlist for some page-aligned vmalloc()'ed memory + * block (NULL on errors). Memory for the scatterlist is allocated + * using kmalloc. The caller must free the memory. + */ +struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); + +/* + * Return a scatterlist for a an array of userpages (NULL on errors). + * Memory for the scatterlist is allocated using kmalloc. The caller + * must free the memory. + */ +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage buffers (both userland + * and kernel) for DMA. + * + * videobuf_dma_init_*() + * creates a buffer. The userland version takes a userspace + * pointer + length. The kernel version just wants the size and + * does memory allocation too using vmalloc_32(). + * + * videobuf_dma_*() + * see Documentation/DMA-mapping.txt, these functions to + * basically the same. The map function does also build a + * scatterlist for the buffer (and unmap frees it ...) + * + * videobuf_dma_free() + * no comment ... + * + */ + +struct videobuf_dmabuf { + u32 magic; + + /* for userland buffer */ + int offset; + struct page **pages; + + /* for kernel buffers */ + void *vmalloc; + + /* Stores the userspace pointer to vmalloc area */ + void *varea; + + /* for overlay buffers (pci-pci dma) */ + dma_addr_t bus_addr; + + /* common */ + struct scatterlist *sglist; + int sglen; + int nr_pages; + int direction; +}; + +struct videbuf_pci_sg_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + struct videobuf_dmabuf dma; +}; + +/* FIXME: To be removed soon */ +typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, + int direction); + +/* FIXME: To be removed soon */ +struct videobuf_dma_sg_ops +{ + vb_map_sg_t *vb_map_sg; + vb_map_sg_t *vb_dma_sync_sg; + vb_map_sg_t *vb_unmap_sg; + +}; + +void videobuf_dma_init(struct videobuf_dmabuf *dma); +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size); +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages); +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages); +int videobuf_dma_free(struct videobuf_dmabuf *dma); + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf); + +void *videobuf_pci_alloc (size_t size); + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + + /*FIXME: these variants are used only on *-alsa code, where videobuf is + * used without queue + */ +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); + +/* FIXME: temporary routine for vivi and tm6000, while lacking implementation + * of videobuf-vmalloc + */ +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops); + From c1accaa21bdef38ec0f36eaaf7ce3384fff9d0c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:37:49 -0300 Subject: [PATCH 259/310] V4L/DVB (6252): Adapt drivers to use the newer videobuf modules PCI-dependent videobuf_foo methods were renamed as videobuf_pci_foo. Also, videobuf_dmabuf is now part of videobuf-dma-sg private struct. So, to access it, a subroutine call is needed. This patch renames all occurences of those function calls to be consistent with the video-buf split. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- Documentation/dvb/faq.txt | 2 +- drivers/media/Kconfig | 6 ++- drivers/media/common/Kconfig | 2 +- drivers/media/common/saa7146_core.c | 2 +- drivers/media/common/saa7146_fops.c | 5 ++- drivers/media/common/saa7146_vbi.c | 9 +++-- drivers/media/common/saa7146_video.c | 9 +++-- drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 3 +- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 17 +++++---- drivers/media/video/bt8xx/bttv-risc.c | 35 +++++++++-------- drivers/media/video/bt8xx/bttv-vbi.c | 5 ++- drivers/media/video/bt8xx/bttvp.h | 2 +- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/cx88/cx88-alsa.c | 24 +++++++----- drivers/media/video/cx88/cx88-blackbird.c | 2 +- drivers/media/video/cx88/cx88-core.c | 6 ++- drivers/media/video/cx88/cx88-dvb.c | 2 +- drivers/media/video/cx88/cx88-mpeg.c | 3 +- drivers/media/video/cx88/cx88-vbi.c | 3 +- drivers/media/video/cx88/cx88-video.c | 38 +++++-------------- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- drivers/media/video/saa7134/saa7134-core.c | 8 ++-- drivers/media/video/saa7134/saa7134-dvb.c | 2 +- drivers/media/video/saa7134/saa7134-empress.c | 2 +- drivers/media/video/saa7134/saa7134-ts.c | 6 ++- drivers/media/video/saa7134/saa7134-vbi.c | 6 ++- drivers/media/video/saa7134/saa7134-video.c | 34 ++++------------- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 6 ++- include/media/saa7146_vv.h | 2 +- 34 files changed, 125 insertions(+), 130 deletions(-) diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt index dbcedf5833ee..2511a335abd6 100644 --- a/Documentation/dvb/faq.txt +++ b/Documentation/dvb/faq.txt @@ -150,7 +150,7 @@ Some very frequently asked questions about linuxtv-dvb - saa7146_vv: SAA7146 video and vbi functions. These are only needed for full-featured cards. - - video-buf: capture helper module for the saa7146_vv driver. This + - videobuf-dma-sg: capture helper module for the saa7146_vv driver. This one is responsible to handle capture buffers. - dvb-ttpci: The main driver for AV7110 based, full-featured diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3f8cfa873de5..28ee65c53917 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -126,8 +126,12 @@ config TUNER_SIMPLE endif # VIDEO_TUNER_CUSTOMIZE -config VIDEO_BUF +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG depends on PCI + select VIDEOBUF_GEN tristate config VIDEO_BUF_DVB diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 5c63c8e24ee7..c5092ef1082f 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -5,5 +5,5 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate depends on VIDEO_DEV - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 1c962a2b44df..365a22118a09 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c make sure virt has been allocated with vmalloc_32(), otherwise the BUG() may be triggered on highmem machines */ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index b4770aecc01d..67d1b1b1b254 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct saa7146_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); DEB_EE(("dev:%p, buf:%p\n",dev,buf)); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 063608462ebe..6103484e4442 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf /* we don't wait here for the first field anymore. this is different from the video capture and might cause that the first buffer is only half filled (with only one field). but since this is some sort of streaming data, this is not that negative. - but by doing this, we can use the whole engine from video-buf.c... */ + but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ /* WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); @@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e saa7146_dma_free(dev,q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e err = videobuf_iolock(q,&buf->vb, NULL); if (err) goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen); + err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + dma->sglist, dma->sglen); if (0 != err) return err; } @@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) fh->vbi_fmt.start[1] = 312; fh->vbi_fmt.count[1] = 16; - videobuf_queue_init(&fh->vbi_q, &vbi_qops, + videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, // FIXME: does this really work? diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 664280c78ff2..29dbc602a484 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) { struct pci_dev *pci = dev->pci; - struct scatterlist *list = buf->vb.dma.sglist; - int length = buf->vb.dma.sglen; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + struct scatterlist *list = dma->sglist; + int length = dma->sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = buf->vb.dma.sglist->offset; + pt1->offset = list->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; @@ -1411,7 +1412,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; - videobuf_queue_init(&fh->video_q, &video_qops, + videobuf_queue_pci_init(&fh->video_q, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5d74925748c0..c4f424422f70 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEO_BUF + select VIDEOBUF_DMA_SG default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9e99d2e1c1bd..cb300241eb89 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -87,7 +87,8 @@ obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_VIDEO_BUF) += video-buf.o +obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o +obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 58eae887a629..2ca162b390a2 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_BT848 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0711c9507843..4ab4e14b5c64 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2582,7 +2582,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); @@ -3048,7 +3048,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_lock(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { @@ -3141,9 +3141,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EIO; /* fall through */ case STATE_DONE: - videobuf_dma_sync(&fh->cap,&buf->vb.dma); + { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + videobuf_dma_sync(&fh->cap,dma); bttv_dma_free(&fh->cap,btv,buf); break; + } default: retval = -EINVAL; break; @@ -3337,7 +3340,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); retval = bttv_switch_overlay(btv,fh,new); @@ -3696,7 +3699,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) mutex_unlock(&fh->cap.lock); return POLLERR; } - fh->cap.read_buf = videobuf_alloc(fh->cap.msize); + fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) { mutex_unlock(&fh->cap.lock); return POLLERR; @@ -3763,13 +3766,13 @@ static int bttv_open(struct inode *inode, struct file *file) fh->ov.setup_ok = 0; v4l2_prio_open(&btv->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &bttv_video_qops, + videobuf_queue_pci_init(&fh->cap, &bttv_video_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), fh); - videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index e7104d9cb4bd..58986f1a5f1a 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = STATE_NEEDS_INIT; @@ -699,6 +701,7 @@ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) { const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", @@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) switch (buf->vb.field) { case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, /* offset */ 0,bpl, /* padding */ 0,/* skip_lines */ 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, 0,bpl,0,0,buf->vb.height); break; case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpl,bpl,bpl,0,buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpf,bpl,0,0,buf->vb.height >> 1); break; default: @@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,/* both_fields */ 0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->top, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->bottom, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,ypadding,lines, uoffset,voffset, buf->fmt->hshift, buf->fmt->vshift, cpadding); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, @@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1, @@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->fmt->vshift, 0); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, lines * ypadding,buf->vb.width,0,lines, lines * ypadding + (uoffset >> 1), lines * ypadding + (voffset >> 1), @@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->top, dma->sglist, /* offset */ 0, RAW_BPL, /* padding */ 0, /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->bottom, dma->sglist, buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); } diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 007485aa4f01..346ce019bdcb 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -150,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, if (redo_dma_risc) { unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); bpl = 2044; /* max. vbipack */ padding = VBI_BPL - bpl; if (fh->vbi_fmt.fmt.count[0] > 0) { rc = bttv_risc_packed(btv, &buf->top, - buf->vb.dma.sglist, + dma->sglist, /* offset */ 0, bpl, padding, skip_lines0, fh->vbi_fmt.fmt.count[0]); @@ -168,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; rc = bttv_risc_packed(btv, &buf->bottom, - buf->vb.dma.sglist, + dma->sglist, offset, bpl, padding, skip_lines1, fh->vbi_fmt.fmt.count[1]); diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 5b25faca1504..0b92c35a8435 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ccb37006bb18..b63cab336920 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1197,7 +1197,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index) buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; /* - * Offset: must be 32-bit even on a 64-bit system. video-buf + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg * just uses the length times the index, but the spec warns * against doing just that - vma merging problems. So we * leave a gap between each pair of buffers. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index f750a543c961..c68ba74d44ec 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CX88 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f4abed454fd4..90c36c5705c3 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -72,7 +72,7 @@ struct cx88_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf *dma_risc; struct cx88_buffer *buf; @@ -282,11 +282,12 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) BUG_ON(!chip->dma_size); dprintk(2,"Freeing buffer\n"); - videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc); - videobuf_dma_free(&chip->dma_risc); + videobuf_pci_dma_unmap(chip->pci, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); btcx_riscmem_free(chip->pci,&chip->buf->risc); kfree(chip->buf); + chip->dma_risc = NULL; chip->dma_size = 0; return 0; @@ -366,6 +367,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + struct cx88_buffer *buf; int ret; @@ -381,7 +384,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, BUG_ON(!chip->dma_size); BUG_ON(chip->num_periods & (chip->num_periods-1)); - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = videobuf_pci_alloc(sizeof(*buf)); if (NULL == buf) return -ENOMEM; @@ -392,17 +395,18 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - videobuf_dma_init(&buf->vb.dma); - ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, + dma=videobuf_to_dma(&buf->vb); + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,dma); if (ret < 0) goto error; - ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, buf->vb.width, buf->vb.height, 1); if (ret < 0) goto error; @@ -414,9 +418,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.state = STATE_PREPARED; chip->buf = buf; - chip->dma_risc = buf->vb.dma; + chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_area = chip->dma_risc->vmalloc; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fcaf4f51293f..6d6f5048d762 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1111,7 +1111,7 @@ static int mpeg_open(struct inode *inode, struct file *file) file->private_data = fh; fh->dev = dev; - videobuf_queue_init(&fh->mpegq, &blackbird_qops, + videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 716154828ff0..85609b41f86e 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -213,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 00d0e43785a0..d16e5c6d21c0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -710,7 +710,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d302793fcfb9..a652f294d23d 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -237,6 +237,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, struct cx88_buffer *buf, enum v4l2_field field) { int size = dev->ts_packet_size * dev->ts_packet_count; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc; dprintk(1, "%s: %p\n", __FUNCTION__, buf); @@ -252,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 72c1d19fa79f..aa40505c4b3a 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -172,6 +172,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; buf->vb.size = size; @@ -180,7 +181,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, buf->vb.height); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 705c29b002ea..1439b7268532 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -534,6 +534,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); @@ -566,30 +567,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, switch (buf->vb.field) { case V4L2_FIELD_TOP: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, UNSET, + dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, UNSET, 0, + dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, buf->bpl, + dma->sglist, 0, buf->bpl, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->bpl * (buf->vb.height >> 1), buf->bpl, 0, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_BT: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->bpl * (buf->vb.height >> 1), 0, buf->bpl, 0, buf->vb.height >> 1); @@ -752,13 +753,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - videobuf_queue_init(&fh->vidq, &cx8800_video_qops, + videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx88_buffer), fh); - videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops, + videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -1104,28 +1105,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, #ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { - struct cx8800_fh *fh = priv; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - int err; + struct cx8800_fh *fh = priv; - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; + return videobuf_cgmbuf (get_queue(fh), mbuf, 8); } #endif diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0e4f8e278671..875a9abab2a2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 9f1417a4f7d2..82bc4ef414ac 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -1,7 +1,7 @@ config VIDEO_SAA7134 tristate "Philips SAA7134 support" depends on VIDEO_DEV && PCI && I2C - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select CRC32 diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80108ddf4834..a1d986e01a30 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -236,9 +236,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf) unsigned long saa7134_buffer_base(struct saa7134_buf *buf) { unsigned long base; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); base = saa7134_buffer_startpage(buf) * 4096; - base += buf->vb.dma.sglist[0].offset; + base += dma->sglist[0].offset; return base; } @@ -286,11 +287,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index bbab252cbeee..38d87332cc5d 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -850,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev) dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; dev->dvb.name = dev->name; - videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 7ed4eaf05e13..a16df57af63a 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -400,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->empress_dev->minor & 0x1f); - videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 7780b2cce80d..5b1d1dafb5a5 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -92,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -101,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 0044079f5da2..81a2aedeff5c 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -137,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -146,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9c317ed6b210..cf40a9690a50 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1037,6 +1037,8 @@ static int buffer_prepare(struct videobuf_queue *q, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; @@ -1048,8 +1050,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; @@ -1309,13 +1311,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 576; v4l2_prio_open(&dev->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &video_qops, + videobuf_queue_pci_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7134_buf), fh); - videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -2137,29 +2139,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = saa7134_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = gbuffers; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } + return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); #endif case VIDIOC_REQBUFS: return videobuf_reqbufs(saa7134_queue(fh),arg); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fd12942b3a10..dae608f9bf3b 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index d2af82dc8faf..9631ead297ee 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include /* ------------------------------------------------------------------ */ @@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer *buf; unsigned long flags; int err; + struct videobuf_dmabuf *dma; dprintk("dvb thread started\n"); set_freezable(); @@ -65,8 +66,9 @@ static int videobuf_dvb_thread(void *data) try_to_freeze(); /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc, + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); /* requeue buffer */ diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index cce20ed5cf6c..e49f7e156061 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ From 6bb2790f8a0cf93d3dbed6b6e986441110e6174b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:41:14 -0300 Subject: [PATCH 260/310] V4L/DVB (6253): Convert vivi to use the newer videobuf-dma-sg module Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 53 ++++++++++++++------------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c10169e35753..89c40341007f 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -327,19 +327,21 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int wmax = buf->vb.width; struct timeval ts; char *tmpbuf; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - if (buf->vb.dma.varea) { + + if (dma->varea) { tmpbuf=kmalloc (wmax*2, GFP_KERNEL); } else { - tmpbuf=buf->vb.dma.vmalloc; + tmpbuf=dma->vmalloc; } for (h=0;hvb.dma.varea) { + if (dma->varea) { gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0) + if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); } else { gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); @@ -369,7 +371,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)buf->vb.dma.varea,pos); + (unsigned long)dma->varea,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -597,13 +599,19 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) if (0 == *count) *count = 32; + while (*size * *count > vid_limit * 1024 * 1024) (*count)--; + + dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); + return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) @@ -611,8 +619,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } @@ -626,7 +634,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); int rc, init_buffer = 0; -// dprintk(1,"%s, field=%d\n",__FUNCTION__,field); + dprintk(1,"%s, field=%d\n",__FUNCTION__,field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -724,11 +732,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release, - - /* Non-pci handling routines */ -// .vb_map_sg = vivi_map_sg, -// .vb_dma_sync_sg = vivi_dma_sync_sg, -// .vb_unmap_sg = vivi_unmap_sg, }; /* ------------------------------------------------------------------ @@ -904,25 +907,8 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; - struct videobuf_queue *q=&fh->vb_vidq; - struct v4l2_requestbuffers req; - unsigned int i; - int ret; - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - ret = videobuf_reqbufs(q,&req); - if (ret < 0) - return (ret); - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return (0); + return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); } #endif @@ -1106,12 +1092,13 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); + return 0; } From 87b9ad070cf76c0f1e8cf836f7eb86e9ac94e34a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:33 -0300 Subject: [PATCH 261/310] V4L/DVB (6254): Add videobuf-vmalloc Adds a newer videobuf-vmalloc module. This module uses the same videobuf controls, but implements memory allocation based on vmalloc methods. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 4 + drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 1 + drivers/media/video/videobuf-vmalloc.c | 384 +++++++++++++++++++++++++ include/media/videobuf-vmalloc.h | 44 +++ 5 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/videobuf-vmalloc.c create mode 100644 include/media/videobuf-vmalloc.h diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 28ee65c53917..fc3ea4c67ccb 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -134,6 +134,10 @@ config VIDEOBUF_DMA_SG select VIDEOBUF_GEN tristate +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + config VIDEO_BUF_DVB tristate diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c4f424422f70..2e571eb9313a 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEOBUF_DMA_SG + select VIDEOBUF_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index cb300241eb89..c8140aec1a16 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c new file mode 100644 index 000000000000..993d5285e18e --- /dev/null +++ b/drivers/media/video/videobuf-vmalloc.c @@ -0,0 +1,384 @@ +/* + * helper functions for vmalloc video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x17760309 +#define MAGIC_VMAL_MEM 0x18221223 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + + +/***************************************************************************/ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_vmalloc_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, +}; + +/* --------------------------------------------------------------------- + * vmalloc handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_VMAL_MEM; + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int pages; + + struct videbuf_vmalloc_memory *mem=vb->priv; + + + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + + /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ + if ((vb->memory != V4L2_MEMORY_MMAP) && + (vb->memory != V4L2_MEMORY_USERPTR) ) { + printk(KERN_ERR "Method currently unsupported.\n"); + return -EINVAL; + } + + /* FIXME: should be tested with kernel mmap mem */ + mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); + if (NULL == mem->vmalloc) { + dprintk(1,"vmalloc (%d pages) failed\n",pages); + return -ENOMEM; + } + + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)mem->vmalloc, + pages << PAGE_SHIFT); + + /* It seems that some kernel versions need to do remap *after* + the mmap() call + */ + if (mem->vma) { + int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); + kfree(mem->vma); + mem->vma=NULL; + if (retval<0) { + dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", + mem->vmalloc,retval); + return retval; + } + } + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + return 0; +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + unsigned int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_mapping *map; + unsigned int first; + int retval; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == offset) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + return -EINVAL; + } + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + /* create mapping + update buffer list */ + map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + return -ENOMEM; + + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + q->bufs[first]->baddr = vma->vm_start; + + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = map; + + /* Try to remap memory */ + retval=remap_vmalloc_range(vma, mem->vmalloc,0); + if (retval<0) { + dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); + if (!mem->vma) { + kfree(map); + mem->map=NULL; + return -ENOMEM; + } + memcpy(mem->vma,vma,sizeof(*vma)); + } + + dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", + map,q,vma->vm_start,vma->vm_end, + (long int) q->bufs[first]->bsize, + vma->vm_pgoff,first); + + videobuf_vm_open(vma); + + return (0); +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + BUG_ON (!mem->vmalloc); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops qops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&qops; +} + +EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return mem->vmalloc; +} +EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + vfree(mem->vmalloc); + + return; +} +EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h new file mode 100644 index 000000000000..5fff68df6689 --- /dev/null +++ b/include/media/videobuf-vmalloc.h @@ -0,0 +1,44 @@ +/* + * helper functions for vmalloc capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include + +/* --------------------------------------------------------------------- */ + +struct videbuf_vmalloc_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + + void *vmalloc; + + /* remap_vmalloc_range seems to need to run after mmap() on some cases */ + struct vm_area_struct *vma; +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf); From 5a0377060efcf844f4e359f3ab013de7f1b98da2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:54 -0300 Subject: [PATCH 262/310] V4L/DVB (6255): Convert vivi to use videobuf-vmalloc This patch removes the usage of videobuf-dma-sg from vivi driver, using instead videobuf-vmalloc. This way, vivi will be useful for testing the newer method. Reverting this patch won't hurt vivi, since both methods work fine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 44 +++++++++++++------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 89c40341007f..c14e2b3e4241 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -145,7 +145,6 @@ struct vivi_buffer { struct videobuf_buffer vb; struct vivi_fmt *fmt; - }; struct vivi_dmaqueue { @@ -326,29 +325,22 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - - if (dma->varea) { - tmpbuf=kmalloc (wmax*2, GFP_KERNEL); - } else { - tmpbuf=dma->vmalloc; - } + char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); + void *vbuf=videobuf_to_vmalloc (&buf->vb); + if (!tmpbuf) + return; for (h=0;hvarea) { - gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); - /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) - dprintk(2,"vivifill copy_to_user failed.\n"); - } else { - gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); - } + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); + /* FIXME: replacing to __copy_to_user */ + if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) + dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + kfree(tmpbuf); + /* Updates stream time */ dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); @@ -371,7 +363,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)dma->varea,pos); + (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -610,17 +602,13 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, dma); - videobuf_dma_free(dma); + videobuf_vmalloc_free(&buf->vb); buf->vb.state = STATE_NEEDS_INIT; } @@ -726,7 +714,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } - static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, @@ -1092,13 +1079,12 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); - return 0; } @@ -1192,7 +1178,7 @@ static const struct file_operations vivi_fops = { .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vivi_mmap, + .mmap = vivi_mmap, .llseek = no_llseek, }; From 79618cf41337ccedb9abeee059ce76aac7962739 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:31:15 -0300 Subject: [PATCH 263/310] V4L/DVB (6256): Remove the obsolete video-buf module Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/video-buf.c | 1424 ------------------------------- include/media/video-buf.h | 289 ------- 2 files changed, 1713 deletions(-) delete mode 100644 drivers/media/video/video-buf.c delete mode 100644 include/media/video-buf.h diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c deleted file mode 100644 index f6f31e1773d1..000000000000 --- a/drivers/media/video/video-buf.c +++ /dev/null @@ -1,1424 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001-2004 Gerd Knorr [SUSE Labs] - * (c) 2006 Mauro Carvalho Chehab - * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_BUFFER 0x20040302 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } - -static int debug = 0; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) - -struct scatterlist* -videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - err: - kfree(sglist); - return NULL; -} - -struct scatterlist* -videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) -{ - struct scatterlist *sglist; - int i = 0; - - if (NULL == pages[0]) - return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - - if (NULL == pages[0]) - goto nopage; - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sglist[0].page = pages[0]; - sglist[0].offset = offset; - sglist[0].length = PAGE_SIZE - offset; - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sglist[i].page = pages[i]; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - nopage: - dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); - return NULL; - - highmem: - dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma,0,sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - unsigned long first,last; - int err, rw = 0; - - dma->direction = direction; - switch (dma->direction) { - case PCI_DMA_FROMDEVICE: rw = READ; break; - case PCI_DMA_TODEVICE: rw = WRITE; break; - default: BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", - data,size,dma->nr_pages); - - dma->varea = (void *) data; - - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current,current->mm, - data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); - up_read(¤t->mm->mmap_sem); - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages) -{ - dprintk(1,"init kernel [%d pages]\n",nr_pages); - dma->direction = direction; - dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == dma->vmalloc) { - dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); - return -ENOMEM; - } - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vmalloc, - nr_pages << PAGE_SHIFT); - memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages) -{ - dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", - nr_pages,(unsigned long)addr); - dma->direction = direction; - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset); - } - if (dma->vmalloc) { - dma->sglist = videobuf_vmalloc_to_sg - (dma->vmalloc,dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1,"scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - if (q->ops->vb_map_sg) { - dma->sglen = q->ops->vb_map_sg(dev,dma->sglist, - dma->nr_pages, dma->direction); - } - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n",__FUNCTION__); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -EIO; - } - } - return 0; -} - -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(!dma->sglen); - - if (!dma->bus_addr && q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - - return 0; -} - -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - if (!dma->sglen) - return 0; - - if (!dma->bus_addr && q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return 0; -} - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - int i; - for (i=0; i < dma->nr_pages; i++) - page_cache_release(dma->pages[i]); - kfree(dma->pages); - dma->pages = NULL; - } - - vfree(dma->vmalloc); - dma->vmalloc = NULL; - dma->varea = NULL; - - if (dma->bus_addr) { - dma->bus_addr = 0; - } - dma->direction = PCI_DMA_NONE; - return 0; -} - -/* --------------------------------------------------------------------- */ - -void* videobuf_alloc(unsigned int size) -{ - struct videobuf_buffer *vb; - - vb = kzalloc(size,GFP_KERNEL); - if (NULL != vb) { - videobuf_dma_init(&vb->dma); - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - return vb; -} - -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) -{ - int retval = 0; - DECLARE_WAITQUEUE(wait, current); - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { - if (non_blocking) { - retval = -EAGAIN; - break; - } - set_current_state(intr ? TASK_INTERRUPTIBLE - : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) - schedule(); - set_current_state(TASK_RUNNING); - if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); - retval = -EINTR; - break; - } - } - remove_wait_queue(&vb->done, &wait); - return retval; -} - -int -videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - int err,pages; - dma_addr_t bus; - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE, - pages); - if (0 != err) - return err; - } else { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE, - vb->baddr,vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q,&vb->dma); - if (0 != err) - return err; - - return 0; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_queue_pci(struct videobuf_queue* q) -{ - /* If not specified, defaults to PCI map sg */ - if (!q->ops->vb_map_sg) - q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_map(&q,dma)); -} - -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_unmap(&q,dma)); -} - -void videobuf_queue_init(struct videobuf_queue* q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv) -{ - memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - - videobuf_queue_pci(q); - - mutex_init(&q->lock); - INIT_LIST_HEAD(&q->stream); -} - -int -videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - if (q->streaming) { - dprintk(1,"busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1,"busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); - return 1; - } - } - return 0; -} - -void -videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags=0; - int i; - - /* remove queued buffers from list */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == STATE_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; - } - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} - -/* --------------------------------------------------------------------- */ - -enum v4l2_field -videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} - -void -videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - } - - b->flags = 0; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case STATE_DONE: - case STATE_ERROR: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case STATE_NEEDS_INIT: - case STATE_IDLE: - /* nothing */ - break; - } - - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - - b->field = vb->field; - b->timestamp = vb->ts; - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int -videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size,count; - int retval; - - if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); - return -EINVAL; - } - if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); - return -EINVAL; - } - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; - } - if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; - } - - mutex_lock(&q->lock); - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q,&count,&size); - size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", - count, size, (count*size)>>PAGE_SHIFT); - - retval = videobuf_mmap_setup(q,count,size,req->memory); - if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); - goto done; - } - - req->count = count; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); - return -EINVAL; - } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); - return -EINVAL; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); - return -EINVAL; - } - videobuf_status(b,q->bufs[b->index],q->type); - return 0; -} - -int -videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); - goto done; - } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); - goto done; - } - - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); - goto done; - } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1,"qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1,"qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); - if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); - goto done; - } - - list_add_tail(&buf->stream,&q->stream); - if (q->streaming) { - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - } - dprintk(1,"qbuf: succeded\n"); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); - goto done; - } - if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); - goto done; - } - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, nonblocking, 1); - if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); - goto done; - } - switch (buf->state) { - case STATE_ERROR: - dprintk(1,"dqbuf: state is error\n"); - retval = -EIO; - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - case STATE_DONE: - dprintk(1,"dqbuf: state is done\n"); - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - default: - dprintk(1,"dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(b,buf,q->type); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - struct list_head *list; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); - if (buf->state == STATE_PREPARED) - q->ops->buf_queue(q,buf); - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval = -EINVAL; - - mutex_lock(&q->lock); - if (!q->streaming) - goto done; - videobuf_queue_cancel(q); - q->streaming = 0; - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -static ssize_t -videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags=0; - int retval; - - /* setup stuff */ - q->read_buf = videobuf_alloc(q->msize); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) - goto done; - - /* start capture & wait */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); - if (0 == retval) { - videobuf_dma_sync(q,&q->read_buf->dma); - if (STATE_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - - done: - /* cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags=0; - unsigned size, nbufs, bytes; - int retval; - - mutex_lock(&q->lock); - - nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc(q->msize); - dprintk(1,"video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) { - kfree (q->read_buf); - q->read_buf = NULL; - goto done; - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - videobuf_dma_sync(q,&q->read_buf->dma); - - if (STATE_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* copy to userspace */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - retval = -EFAULT; - if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes)) - goto done; - - retval = bytes; - q->read_off += bytes; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags=0; - int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q,&count,&size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) - return err; - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->reading = 1; - return 0; -} - -void videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - videobuf_mmap_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; - q->reading = 0; -} - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - unsigned int *fc, bytes; - int err, retval; - unsigned long flags=0; - - dprintk(2,"%s\n",__FUNCTION__); - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - err = videobuf_waiton(q->read_buf, nonblocking, 1); - if (err < 0) { - if (0 == retval) - retval = err; - break; - } - - if (q->read_buf->state == STATE_DONE) { - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc = (unsigned int*)q->read_buf->dma.vmalloc; - fc += (q->read_buf->size>>2) -1; - *fc = q->read_buf->field_count >> 1; - dprintk(1,"vbihack: %d\n",*fc); - } - - /* copy stuff */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - if (copy_to_user(data + retval, - q->read_buf->dma.vmalloc + q->read_off, - bytes)) { - if (0 == retval) - retval = -EFAULT; - break; - } - count -= bytes; - retval += bytes; - q->read_off += bytes; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - mutex_lock(&q->lock); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else { - if (!q->reading) - videobuf_read_start(q); - if (!q->reading) { - rc = POLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (!buf) - rc = POLLERR; - - if (0 == rc) { - poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) - rc = POLLIN|POLLRDNORM; - } - mutex_unlock(&q->lock); - return rc; -} - -/* --------------------------------------------------------------------- */ - -static void -videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - map->count++; -} - -static void -videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]) - ; - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); - } - mutex_unlock(&q->lock); - kfree(map); - } - return; -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) -{ - struct page *page; - - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; -} - -static struct vm_operations_struct videobuf_vm_ops = -{ - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, -}; - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - err = videobuf_mmap_free(q); - if (0 != err) - return err; - - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc(q->msize); - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = bsize * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); - return 0; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) - return -EBUSY; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - return 0; -} - -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma) -{ - struct videobuf_mapping *map; - unsigned int first,last,size,i; - int retval; - - mutex_lock(&q->lock); - retval = -EINVAL; - if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1,"mmap app bug: PROT_WRITE please\n"); - goto done; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1,"mmap app bug: MAP_SHARED please\n"); - goto done; - } - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (NULL == q->bufs[first]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) - continue; - if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - if (VIDEO_MAX_FRAME == first) { - dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - /* look for last buffer to map */ - for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { - if (NULL == q->bufs[last]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) - continue; - if (q->bufs[last]->map) { - retval = -EBUSY; - goto done; - } - size += q->bufs[last]->bsize; - if (size == (vma->vm_end - vma->vm_start)) - break; - } - if (VIDEO_MAX_FRAME == last) { - dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", - (vma->vm_end - vma->vm_start)); - goto done; - } - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); - if (NULL == map) - goto done; - for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - } - map->count = 1; - map->start = vma->vm_start; - map->end = vma->vm_end; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ - vma->vm_private_data = map; - dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); - -EXPORT_SYMBOL_GPL(videobuf_dma_init); -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -EXPORT_SYMBOL_GPL(videobuf_dma_map); -EXPORT_SYMBOL_GPL(videobuf_dma_sync); -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); -EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); - -EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_waiton); -EXPORT_SYMBOL_GPL(videobuf_iolock); - -EXPORT_SYMBOL_GPL(videobuf_queue_init); -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -EXPORT_SYMBOL_GPL(videobuf_next_field); -EXPORT_SYMBOL_GPL(videobuf_status); -EXPORT_SYMBOL_GPL(videobuf_reqbufs); -EXPORT_SYMBOL_GPL(videobuf_querybuf); -EXPORT_SYMBOL_GPL(videobuf_qbuf); -EXPORT_SYMBOL_GPL(videobuf_dqbuf); -EXPORT_SYMBOL_GPL(videobuf_streamon); -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -EXPORT_SYMBOL_GPL(videobuf_read_start); -EXPORT_SYMBOL_GPL(videobuf_read_stop); -EXPORT_SYMBOL_GPL(videobuf_read_stream); -EXPORT_SYMBOL_GPL(videobuf_read_one); -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); -EXPORT_SYMBOL_GPL(videobuf_mmap_free); -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/video-buf.h b/include/media/video-buf.h deleted file mode 100644 index d6f079476db3..000000000000 --- a/include/media/video-buf.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as file operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include - -#define UNSET (-1U) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, - int offset); - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/DMA-mapping.txt, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - struct page **pages; - - /* for kernel buffers */ - void *vmalloc; - - /* Stores the userspace pointer to vmalloc area */ - void *varea; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - int nr_pages; - int direction; -}; - -void videobuf_dma_init(struct videobuf_dmabuf *dma); -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages); -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); - - /*FIXME: these variants are used only on *-alsa code, where videobuf is - * used without queue - */ -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contingous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be feeded into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - unsigned long start; - unsigned long end; - struct videobuf_queue *q; -}; - -enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - unsigned int input; - enum v4l2_field field; - enum videobuf_state state; - struct videobuf_dmabuf dma; - struct list_head stream; /* QBUF/DQBUF list */ - - /* for mmap'ed buffers */ - enum v4l2_memory memory; - size_t boff; /* buffer offset (mmap + overlay) */ - size_t bsize; /* buffer size */ - unsigned long baddr; /* buffer addr (userland ptr!) */ - struct videobuf_mapping *map; - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - struct timeval ts; -}; - -typedef int (vb_map_sg_t)(void *dev,struct scatterlist *sglist,int nr_pages, - int direction); - - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - - /* Helper operations - device dependent. - * If null, videobuf_init defaults all to PCI handling - */ - - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; -}; - -struct videobuf_queue { - struct mutex lock; - spinlock_t *irqlock; - void *dev; /* on pci, points to struct pci_dev */ - - enum v4l2_buf_type type; - unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - struct videobuf_queue_ops *ops; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; - struct list_head stream; - - /* capture via read() */ - unsigned int reading; - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -void* videobuf_alloc(unsigned int size); -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -/* Maps fops to PCI stuff */ -void videobuf_queue_pci(struct videobuf_queue* q); - -void videobuf_queue_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -/* --------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ From ba366a23b68029fc8560acf1ad8735eed910f962 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 18:12:08 -0300 Subject: [PATCH 264/310] V4L/DVB (6257): Rename video-buf-dvb to videobuf-dvb to be consistent with the other patches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 +- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/{video-buf-dvb.c => videobuf-dvb.c} | 2 +- include/media/{video-buf-dvb.h => videobuf-dvb.h} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename drivers/media/video/{video-buf-dvb.c => videobuf-dvb.c} (99%) rename include/media/{video-buf-dvb.h => videobuf-dvb.h} (100%) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c8140aec1a16..b5a064163e03 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -90,7 +90,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o -obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o +obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 875a9abab2a2..b3fe2d59cd13 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -32,7 +32,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #include "btcx-risc.h" diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index dae608f9bf3b..cb617c8dbb71 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -42,7 +42,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #define UNSET (-1U) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/videobuf-dvb.c similarity index 99% rename from drivers/media/video/video-buf-dvb.c rename to drivers/media/video/videobuf-dvb.c index 9631ead297ee..880317e04a02 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -23,7 +23,7 @@ #include #include -#include +#include /* ------------------------------------------------------------------ */ diff --git a/include/media/video-buf-dvb.h b/include/media/videobuf-dvb.h similarity index 100% rename from include/media/video-buf-dvb.h rename to include/media/videobuf-dvb.h From 40558dafff257d69248af8b96c7e896f6bc79dfa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 07:37:34 -0300 Subject: [PATCH 265/310] V4L/DVB (6259): Fix vivi poll() method Due to the replace of videobuf_read_one to videobuf_read_stream, poll() method implementation is wrong. This fixes poll() implementation, making read of /dev/video? to work again. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c14e2b3e4241..01c977671311 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1122,9 +1122,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) } else { dprintk(1,"poll: read() interface\n"); /* read() capture */ - buf = (struct vivi_buffer*)fh->vb_vidq.read_buf; - if (NULL == buf) - return POLLERR; + return videobuf_poll_stream(file, &fh-> vb_vidq, + wait); } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == STATE_DONE || From 28318c72adc14952d05d8037d73cec852247791c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Oct 2007 11:16:16 -0300 Subject: [PATCH 266/310] V4L/DVB (6260): Fix Kconfig dependency Thanks to Michael Krufky for pointing this to me. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- drivers/media/video/cx23885/Kconfig | 4 ++-- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index fc3ea4c67ccb..e705265909da 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -138,7 +138,7 @@ config VIDEOBUF_VMALLOC select VIDEOBUF_GEN tristate -config VIDEO_BUF_DVB +config VIDEOBUF_DVB tristate config VIDEO_BTCX diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ebfcc7c2a89e..af60700da8c0 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,11 +4,11 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index c68ba74d44ec..eeb5224ca101 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -46,7 +46,7 @@ config VIDEO_CX88_BLACKBIRD config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" depends on VIDEO_CX88 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 82bc4ef414ac..d6d8d660196d 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -38,7 +38,7 @@ config VIDEO_SAA7134_OSS config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE From c520a4970c7e5f18275ef935372e56eabd6d0e44 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 18:55:07 -0300 Subject: [PATCH 267/310] V4L/DVB (6261): Cleans mem->vmalloc after vfree Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 993d5285e18e..6ef4f523689a 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -372,6 +372,7 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf) MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); vfree(mem->vmalloc); + mem->vmalloc=NULL; return; } From e78dcf55520769471c66024b13df7e9e592436f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 19:08:24 -0300 Subject: [PATCH 268/310] V4L/DVB (6262): An allocation error message were being printed as a debug msg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 6ef4f523689a..b2abfc9d9a8e 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -140,7 +140,6 @@ static int __videobuf_iolock (struct videobuf_queue* q, MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ @@ -153,7 +152,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, /* FIXME: should be tested with kernel mmap mem */ mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); if (NULL == mem->vmalloc) { - dprintk(1,"vmalloc (%d pages) failed\n",pages); + printk(KERN_ERR "vmalloc (%d pages) failed\n",pages); return -ENOMEM; } From 123f8ef64e3996e06a930756b6b2cdede4b18da0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 20:11:35 -0300 Subject: [PATCH 269/310] V4L/DVB (6263): Fix buffer release code Release code should happen before the cleaning of map variable. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index b2abfc9d9a8e..fd059cde63f4 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -84,9 +84,11 @@ videobuf_vm_close(struct vm_area_struct *vma) if (mem->map != map) continue; + + q->ops->buf_release(q,q->bufs[i]); + mem->map = NULL; q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); } mutex_unlock(&q->lock); kfree(map); From 3bef5e4a1f73898dc8c8433f938d3a8b22f2be22 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Sep 2007 02:01:33 -0300 Subject: [PATCH 270/310] V4L/DVB (6264): Make the vertical lines to move While this is not the standard color bar behaviour, having some movement there allows to check if buffers are being properly handled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 01c977671311..650e959aeb78 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -229,9 +229,8 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 - static void gen_line(char *basep,int inipos,int wmax, - int hmax, int line, char *timestr) + int hmax, int line, int count, char *timestr) { int w,i,j,pos=inipos,y; char *p,*s; @@ -242,9 +241,10 @@ static void gen_line(char *basep,int inipos,int wmax, /* Generate a standard color bar pattern */ for (w=0;wvb); + /* FIXME: move to dev struct */ + static int mv_count=0; if (!tmpbuf) return; for (h=0;htimestr); + gen_line(tmpbuf,0,wmax,hmax,h,mv_count, + dev->timestr); /* FIXME: replacing to __copy_to_user */ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + mv_count++; + kfree(tmpbuf); /* Updates stream time */ From cd4765efdd816ac14075fc7d5adf489502e75e1e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 Sep 2007 11:53:24 -0300 Subject: [PATCH 271/310] V4L/DVB (6265): Prevent for calling mmap_free without an allocated buffer Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 256501384af7..eb3b98400c1b 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -880,6 +880,9 @@ int videobuf_mmap_free(struct videobuf_queue *q) int i; int rc; + if (!q) + return 0; + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); rc = CALL(q,mmap_free,q); From 851c0c96b2212f48fe51afc1589541b5eae3a544 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 18:25:44 -0300 Subject: [PATCH 272/310] V4L/DVB (6266): videobuf cleanup: mmap check is common to all videobuf. Make it at core Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 4 +-- drivers/media/video/videobuf-dma-sg.c | 24 ++++------------- drivers/media/video/videobuf-vmalloc.c | 36 +++++++------------------- include/media/videobuf-core.h | 4 ++- include/media/videobuf-dma-sg.h | 1 - include/media/videobuf-vmalloc.h | 3 --- 6 files changed, 20 insertions(+), 52 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index eb3b98400c1b..3bd06bb633a7 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -149,7 +149,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (CALL(q,is_mmapped,q->bufs[i])) { + if (q->bufs[i]->map) { dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } @@ -238,7 +238,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, } b->flags = 0; - if (CALL(q,is_mmapped,vb)) + if (vb->map) b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 3345877c47d4..0939ede831ab 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -374,9 +374,9 @@ videobuf_vm_close(struct vm_area_struct *vma) MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - if (mem->map != map) + if (q->bufs[i]->map != map) continue; - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } @@ -520,8 +520,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -572,8 +571,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, continue; if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) continue; - mem=q->bufs[last]->priv; - if (mem->map) { + if (q->bufs[last]->map) { retval = -EBUSY; goto done; } @@ -593,8 +591,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, if (NULL == map) goto done; for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - mem=q->bufs[i]->priv; - mem->map = map; + q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; } map->count = 1; @@ -613,16 +610,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return retval; } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_pci_sg_memory *mem=buf->priv; - - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -678,7 +665,6 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index fd059cde63f4..c9d6ae0d3b49 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -62,7 +62,6 @@ videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; - struct videbuf_vmalloc_memory *mem; int i; dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, @@ -75,19 +74,13 @@ videobuf_vm_close(struct vm_area_struct *vma) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - mem=q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - if (mem->map != map) + if (q->bufs[i]->map != map) continue; q->ops->buf_release(q,q->bufs[i]); - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } mutex_unlock(&q->lock); @@ -191,8 +184,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -227,12 +219,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); /* create mapping + update buffer list */ - map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); if (NULL == map) return -ENOMEM; @@ -246,14 +235,19 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_private_data = map; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + /* Try to remap memory */ retval=remap_vmalloc_range(vma, mem->vmalloc,0); if (retval<0) { dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); if (!mem->vma) { kfree(map); - mem->map=NULL; + q->bufs[first]->map=NULL; return -ENOMEM; } memcpy(mem->vma,vma,sizeof(*vma)); @@ -269,15 +263,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return (0); } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_vmalloc_memory *mem=buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -335,7 +320,6 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 0ac21ae44f69..96949e31eaf8 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -97,6 +97,9 @@ struct videobuf_buffer { /* buffer addr (userland ptr!) */ unsigned long baddr; + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; @@ -143,7 +146,6 @@ struct videobuf_qtype_ops { int (*mmap_free) (struct videobuf_queue *q); int (*mmap_mapper) (struct videobuf_queue *q, struct vm_area_struct *vma); - int (*is_mmapped) (struct videobuf_buffer *buf); }; struct videobuf_queue { diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 62a3709905f3..206d9027b39f 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -86,7 +86,6 @@ struct videbuf_pci_sg_memory u32 magic; /* for mmap'ed buffers */ - struct videobuf_mapping *map; struct videobuf_dmabuf dma; }; diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index 5fff68df6689..26a8958d23d1 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -21,9 +21,6 @@ struct videbuf_vmalloc_memory { u32 magic; - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - void *vmalloc; /* remap_vmalloc_range seems to need to run after mmap() on some cases */ From 9900132f3437e9373aa030cdb5bd2d5db15566e3 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:09 -0300 Subject: [PATCH 273/310] V4L/DVB (6268): V4L: Fix a lock inversion in generic videobuf code videobuf_qbuf takes q->lock, and then calls q->ops->buf_prepare which by design in all drivers calls videobuf_iolock which calls videobuf_dma_init_user and this takes current->mm->mmap_sem on the other hand if user calls mumap from other thread, sys_munmap takes current->mm->mmap_sem and videobuf_vm_close takes q->lock Since this can occur only for V4L2_MEMORY_MMAP buffers, take current->mm->mmap_sem in qbuf, before q->lock, and don't take current->mm->mmap_sem videobuf_dma_init_user for those buffers Signed-off-by: Maxim Levitsky http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 7 ++++++ drivers/media/video/videobuf-dma-sg.c | 32 ++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 3bd06bb633a7..a27e114cacef 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -349,6 +349,9 @@ int videobuf_qbuf(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + if (b->memory == V4L2_MEMORY_MMAP) + down_read(¤t->mm->mmap_sem); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { @@ -434,6 +437,10 @@ int videobuf_qbuf(struct videobuf_queue *q, done: mutex_unlock(&q->lock); + + if (b->memory == V4L2_MEMORY_MMAP) + up_read(¤t->mm->mmap_sem); + return retval; } diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 0939ede831ab..05dd38343fa3 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -134,8 +134,8 @@ void videobuf_dma_init(struct videobuf_dmabuf *dma) dma->magic = MAGIC_DMABUF; } -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) +static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, + int direction, unsigned long data, unsigned long size) { unsigned long first,last; int err, rw = 0; @@ -160,12 +160,12 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, dma->varea = (void *) data; - down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, rw == READ, 1, /* force */ dma->pages, NULL); - up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); @@ -174,6 +174,17 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, return 0; } +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + int ret; + down_read(¤t->mm->mmap_sem); + ret = videobuf_dma_init_user_locked(dma, direction, data, size); + up_read(¤t->mm->mmap_sem); + + return ret; +} + int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { @@ -469,13 +480,24 @@ static int __videobuf_iolock (struct videobuf_queue* q, pages ); if (0 != err) return err; - } else { + } else if (vb->memory == V4L2_MEMORY_USERPTR) { /* dma directly to userspace */ err = videobuf_dma_init_user( &mem->dma, PCI_DMA_FROMDEVICE, vb->baddr,vb->bsize ); if (0 != err) return err; + } else { + /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP + buffers can only be called from videobuf_qbuf + we take current->mm->mmap_sem there, to prevent + locking inversion, so don't take it here */ + + err = videobuf_dma_init_user_locked(&mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr, vb->bsize); + if (0 != err) + return err; } break; case V4L2_MEMORY_OVERLAY: From b4aeb8b8232bd80764997bf38f574f63e118c259 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:15 -0300 Subject: [PATCH 274/310] V4L/DVB (6269): V4L: Fix a "scheduling while atomic" bug in saa7134 set_tvnorm can sleep in saa7134_i2c_xfer (it will be called through tuner code) but code calls it under spinlock. Fix that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index cf40a9690a50..27c659cd0f30 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1834,7 +1834,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock, flags); + set_tvnorm(dev,&tvnorms[i]); + + spin_lock_irqsave(&dev->slock, flags); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } else From f5a1ac64cc444cf19c8817d61a410b70bbb619d9 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:20 -0300 Subject: [PATCH 275/310] V4L/DVB (6270): V4L: Honor dev->ctl_invert when setting up the decoder in saa7134 When user sets dev->ctl_invert, driver writes negative values to SAA7134_DEC_LUMA_CONTRAST and SAA7134_DEC_CHROMA_SATURATION, but general code that initializes decorder ignores that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 27c659cd0f30..525b5b77c13a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -584,9 +584,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_SYNC_CTRL, sync_control); saa_writeb(SAA7134_LUMA_CTRL, luma_control); saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, + dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); + + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, + dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); + saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); From cb71201f20e43581857043a1f856fb61ce44bdf8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:25 -0300 Subject: [PATCH 276/310] V4L/DVB (6271): V4L: Add basic support for suspend/resume for saa7134 This adds support for suspend/resume for core of saa7134 Should fix bug#7220 Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 175 ++++++++++++++---- drivers/media/video/saa7134/saa7134-ts.c | 23 ++- drivers/media/video/saa7134/saa7134-tvaudio.c | 4 +- drivers/media/video/saa7134/saa7134-video.c | 123 ++++++------ drivers/media/video/saa7134/saa7134.h | 12 ++ 5 files changed, 243 insertions(+), 94 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a1d986e01a30..7f5df32ed0e8 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "saa7134-reg.h" #include "saa7134.h" @@ -392,6 +393,38 @@ void saa7134_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } +/* resends a current buffer in queue after resume */ + +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) +{ + struct saa7134_buf *buf , *next; + unsigned long flags; + + spin_lock_irqsave(&dev->slock, flags); + + buf = q->curr; + next = buf; + + dprintk("buffer_requeue\n"); + + if (!buf) { + spin_unlock_irqrestore(&dev->slock, flags); + return 0; + } + + dprintk("buffer_requeue : resending active buffers \n"); + + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next, struct saa7134_buf, + vb.queue); + + buf->activate(dev, buf, next); + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} + /* ------------------------------------------------------------------ */ int saa7134_set_dmabits(struct saa7134_dev *dev) @@ -647,6 +680,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) /* ------------------------------------------------------------------ */ /* early init (no i2c, no irq) */ + +static int saa7134_hw_enable1(struct saa7134_dev *dev) +{ + /* RAM FIFO config */ + saa_writel(SAA7134_FIFO_SIZE, 0x08070503); + saa_writel(SAA7134_THRESHOULD, 0x02020202); + + /* enable audio + video processing */ + saa_writel(SAA7134_MAIN_CTRL, + SAA7134_MAIN_CTRL_VPLLE | + SAA7134_MAIN_CTRL_APLLE | + SAA7134_MAIN_CTRL_EXOSC | + SAA7134_MAIN_CTRL_EVFE1 | + SAA7134_MAIN_CTRL_EVFE2 | + SAA7134_MAIN_CTRL_ESFE | + SAA7134_MAIN_CTRL_EBDAC); + + /* + * Initialize OSS _after_ enabling audio clock PLL and audio processing. + * OSS initialization writes to registers via the audio DSP; these + * writes will fail unless the audio clock has been started. At worst, + * audio will not work. + */ + + /* enable peripheral devices */ + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + + /* set vertical line numbering start (vbi needs this) */ + saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + + return 0; +} + static int saa7134_hwinit1(struct saa7134_dev *dev) { dprintk("hwinit1\n"); @@ -663,44 +729,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa7134_ts_init1(dev); saa7134_input_init1(dev); - /* RAM FIFO config */ - saa_writel(SAA7134_FIFO_SIZE, 0x08070503); - saa_writel(SAA7134_THRESHOULD,0x02020202); - - /* enable audio + video processing */ - saa_writel(SAA7134_MAIN_CTRL, - SAA7134_MAIN_CTRL_VPLLE | - SAA7134_MAIN_CTRL_APLLE | - SAA7134_MAIN_CTRL_EXOSC | - SAA7134_MAIN_CTRL_EVFE1 | - SAA7134_MAIN_CTRL_EVFE2 | - SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBDAC); - - /* - * Initialize OSS _after_ enabling audio clock PLL and audio processing. - * OSS initialization writes to registers via the audio DSP; these - * writes will fail unless the audio clock has been started. At worst, - * audio will not work. - */ - - /* enable peripheral devices */ - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - - /* set vertical line numbering start (vbi needs this) */ - saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + saa7134_hw_enable1(dev); return 0; } /* late init (with i2c + irq) */ -static int saa7134_hwinit2(struct saa7134_dev *dev) +static int saa7134_hw_enable2(struct saa7134_dev *dev) { - unsigned int irq2_mask; - dprintk("hwinit2\n"); - saa7134_video_init2(dev); - saa7134_tvaudio_init2(dev); + unsigned int irq2_mask; /* enable IRQ's */ irq2_mask = @@ -726,6 +764,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) return 0; } +static int saa7134_hwinit2(struct saa7134_dev *dev) +{ + + dprintk("hwinit2\n"); + + saa7134_video_init2(dev); + saa7134_tvaudio_init2(dev); + + saa7134_hw_enable2(dev); + + return 0; +} + + /* shutdown */ static int saa7134_hwfini(struct saa7134_dev *dev) { @@ -1118,6 +1170,65 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) kfree(dev); } +static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) +{ + + /* Disable card's IRQs to prevent it from resuming computer */ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + saa_writel(SAA7134_IRQ1, 0); + saa_writel(SAA7134_IRQ2, 0); + + + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + pci_save_state(pci_dev); + + return 0; +} + +static int saa7134_resume(struct pci_dev *pci_dev) +{ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); + + /* Do things that are done in saa7134_initdev , + except of initializing memory structures.*/ + + saa7134_board_init1(dev); + + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + if (card_has_mpeg(dev)) + saa7134_ts_init_hw(dev); + + saa7134_hw_enable1(dev); + + saa7134_set_decoder(dev); + + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + + saa7134_board_init2(dev); + saa7134_hw_enable2(dev); + + dev->force_mute_update = 1; + saa7134_tvaudio_setmute(dev); + dev->force_mute_update = 0; + saa7134_tvaudio_setvolume(dev, dev->ctl_volume); + saa7134_enable_i2s(dev); + + /*recapture unfinished buffer(s)*/ + saa7134_buffer_requeue(dev, &dev->video_q); + saa7134_buffer_requeue(dev, &dev->vbi_q); + saa7134_buffer_requeue(dev, &dev->ts_q); + + return 0; +} + /* ----------------------------------------------------------- */ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) @@ -1159,6 +1270,8 @@ static struct pci_driver saa7134_pci_driver = { .id_table = saa7134_pci_tbl, .probe = saa7134_initdev, .remove = __devexit_p(saa7134_finidev), + .suspend = saa7134_suspend, + .resume = saa7134_resume }; static int saa7134_init(void) diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 5b1d1dafb5a5..4b63ad3e8466 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -177,6 +177,22 @@ static unsigned int ts_nr_packets = 64; module_param(ts_nr_packets, int, 0444); MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); +int saa7134_ts_init_hw(struct saa7134_dev *dev) +{ + /* deactivate TS softreset */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + /* TSSOP high active, TSVAL high active, TSLOCK ignored */ + saa_writeb(SAA7134_TS_PARALLEL, 0xec); + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); + saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); + saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, + ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); + + return 0; +} + int saa7134_ts_init1(struct saa7134_dev *dev) { /* sanitycheck insmod options */ @@ -200,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); /* init TS hw */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */ - saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); - saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); - saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); - saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ + saa7134_ts_init_hw(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 43501b5dc05b..df2dab06387d 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in) { + dev->hw_input == in && !dev->force_mute_update) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; @@ -876,7 +876,7 @@ static int tvaudio_thread_ddep(void *data) /* ------------------------------------------------------------------ */ /* common stuff + external entry points */ -static void saa7134_enable_i2s(struct saa7134_dev *dev) +void saa7134_enable_i2s(struct saa7134_dev *dev) { int i2s_format; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 525b5b77c13a..24d579723b55 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -540,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; - mux = card_in(dev,dev->ctl_input).vmux; - luma_control = norm->luma_control; - sync_control = norm->sync_control; - - if (mux > 5) - luma_control |= 0x80; /* svideo */ - if (noninterlaced || dev->nosignal) - sync_control |= 0x20; - /* setup cropping */ dev->crop_bounds.left = norm->h_start; dev->crop_defrect.left = norm->h_start; @@ -570,6 +560,40 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; + saa7134_set_decoder(dev); + + if (card_in(dev, dev->ctl_input).tv) { + if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) + && ((card(dev).tuner_config == 1) + || (card(dev).tuner_config == 2))) + saa7134_set_gpio(dev, 22, 5); + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id); + } +} + +static void video_mux(struct saa7134_dev *dev, int input) +{ + dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); + dev->ctl_input = input; + set_tvnorm(dev, dev->tvnorm); + saa7134_tvaudio_setinput(dev, &card_in(dev, input)); +} + +void saa7134_set_decoder(struct saa7134_dev *dev) +{ + int luma_control, sync_control, mux; + + struct saa7134_tvnorm *norm = dev->tvnorm; + mux = card_in(dev, dev->ctl_input).vmux; + + luma_control = norm->luma_control; + sync_control = norm->sync_control; + + if (mux > 5) + luma_control |= 0x80; /* svideo */ + if (noninterlaced || dev->nosignal) + sync_control |= 0x20; + /* setup video decoder */ saa_writeb(SAA7134_INCR_DELAY, 0x08); saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); @@ -604,23 +628,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); - - /* only tell the tuner if this is a tv input */ - if (card_in(dev,dev->ctl_input).tv) { - if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) - && ((card(dev).tuner_config == 1) - || (card(dev).tuner_config == 2))) - saa7134_set_gpio(dev, 22, 5); - saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); - } -} - -static void video_mux(struct saa7134_dev *dev, int input) -{ - dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); - dev->ctl_input = input; - set_tvnorm(dev,dev->tvnorm); - saa7134_tvaudio_setinput(dev,&card_in(dev,input)); } static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) @@ -2399,34 +2406,40 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->video_q.timeout.data = (unsigned long)(&dev->video_q); dev->video_q.dev = dev; - if (saa7134_boards[dev->board].video_out) { - /* enable video output */ - int vo = saa7134_boards[dev->board].video_out; - int video_reg; - unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; - saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - video_reg = video_out[vo][1]; - if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) - video_reg &= ~VP_T_CODE_P_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - video_reg = video_out[vo][5]; - if (vid_port_opts & SET_CLOCK_NOT_DELAYED) - video_reg &= ~VP_CLK_CTRL2_DELAYED; - if (vid_port_opts & SET_CLOCK_INVERTED) - video_reg |= VP_CLK_CTRL1_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); - video_reg = video_out[vo][6]; - if (vid_port_opts & SET_VSYNC_OFF) { - video_reg &= ~VP_VS_TYPE_MASK; - video_reg |= VP_VS_TYPE_OFF; - } - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + return 0; +} + +int saa7134_videoport_init(struct saa7134_dev *dev) +{ + /* enable video output */ + int vo = saa7134_boards[dev->board].video_out; + int video_reg; + unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; + saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); + video_reg = video_out[vo][1]; + if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) + video_reg &= ~VP_T_CODE_P_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); + video_reg = video_out[vo][5]; + if (vid_port_opts & SET_CLOCK_NOT_DELAYED) + video_reg &= ~VP_CLK_CTRL2_DELAYED; + if (vid_port_opts & SET_CLOCK_INVERTED) + video_reg |= VP_CLK_CTRL1_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); + video_reg = video_out[vo][6]; + if (vid_port_opts & SET_VSYNC_OFF) { + video_reg &= ~VP_VS_TYPE_MASK; + video_reg |= VP_VS_TYPE_OFF; } + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); return 0; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index cb617c8dbb71..5b1f22606558 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,6 +522,7 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; + unsigned int force_mute_update; int last_carrier; int nosignal; @@ -594,6 +595,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q); + int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -626,6 +630,10 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); +int saa7134_videoport_init(struct saa7134_dev *dev); +void saa7134_set_decoder(struct saa7134_dev *dev); + int saa7134_common_ioctl(struct saa7134_dev *dev, unsigned int cmd, void *arg); @@ -649,6 +657,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); int saa7134_ts_register(struct saa7134_mpeg_ops *ops); void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); +int saa7134_ts_init_hw(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-vbi.c */ @@ -677,6 +687,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); +void saa7134_enable_i2s(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-oss.c */ From 11f7078c10944437b6cf335cea50ed7da675a8b1 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:44:39 -0300 Subject: [PATCH 277/310] V4L/DVB (6272): V4L: properly fix support for capturing interlaced video in saa7134 By "capturing interlaced video" I mean that card ensures that top field is really top and vice versa (I think it takes the filed ID from signal) Properly turn on/off that support depending on signal state Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 8 +++++--- drivers/media/video/saa7134/saa7134-video.c | 16 ++++++++++------ drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 7f5df32ed0e8..fae0bfe7939f 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -594,8 +594,10 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); - if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) - saa7134_irq_video_intl(dev); + if ((report & SAA7134_IRQ_REPORT_RDCAP) || + (report & SAA7134_IRQ_REPORT_INTL)) + saa7134_irq_video_signalchange(dev); + if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && (status & 0x60) == 0) @@ -1081,7 +1083,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, mutex_unlock(&devlist_lock); /* check for signal */ - saa7134_irq_video_intl(dev); + saa7134_irq_video_signalchange(dev); if (saa7134_dmasound_init && !dev->dmasound.priv_data) { saa7134_dmasound_init(dev); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 24d579723b55..7c97ac15e665 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -40,7 +40,7 @@ static unsigned int video_debug = 0; static unsigned int gbuffers = 8; -static unsigned int noninterlaced = 1; +static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; static char secam[] = "--"; @@ -2454,7 +2454,7 @@ int saa7134_video_init2(struct saa7134_dev *dev) return 0; } -void saa7134_irq_video_intl(struct saa7134_dev *dev) +void saa7134_irq_video_signalchange(struct saa7134_dev *dev) { static const char *st[] = { "(no signal)", "NTSC", "PAL", "SECAM" }; @@ -2466,24 +2466,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev) (st1 & 0x40) ? "not locked" : "locked", (st2 & 0x40) ? "no" : "yes", st[st1 & 0x03]); - dev->nosignal = (st1 & 0x40) || (st2 & 0x40); + dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); if (dev->nosignal) { /* no video signal -> mute audio */ if (dev->ctl_automute) dev->automute = 1; saa7134_tvaudio_setmute(dev); - saa_setb(SAA7134_SYNC_CTRL, 0x20); } else { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); - if (!noninterlaced) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); } + + if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); + else + saa_setb(SAA7134_SYNC_CTRL, 0x20); + if (dev->mops && dev->mops->signal_change) dev->mops->signal_change(dev); } + void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) { enum v4l2_field field; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 5b1f22606558..745b750cd3fe 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -639,7 +639,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); -void saa7134_irq_video_intl(struct saa7134_dev *dev); +void saa7134_irq_video_signalchange(struct saa7134_dev *dev); void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); From a326ae1126fddd07728e854322e0c657c6b1fbda Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:54:52 -0300 Subject: [PATCH 278/310] V4L/DVB (6273): V4L: vivi.c vidioc_try_fmt_cap() negotiate a valid field If the client provides V4L2_FIELD_ANY vivi should return a valid field :) Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 650e959aeb78..512128a6f58c 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -820,8 +820,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { -// field=V4L2_FIELD_INTERLACED; - field=V4L2_FIELD_SEQ_TB; + field=V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { dprintk(1,"Field type invalid.\n"); return -EINVAL; From 85c7c70bc241d506dffc1879158f77f8aac69734 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:02 -0300 Subject: [PATCH 279/310] V4L/DVB (6274): V4L: vivi.c replace logic in vivi_poll with videobuf_poll_stream Since vivi is using videobuf_read_stream() it can use videobuf_poll_stream() now. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 512128a6f58c..cdef622f6b32 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1111,29 +1111,14 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; struct vivi_buffer *buf; + struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; - if (res_get(fh->dev,fh)) { - dprintk(1,"poll: mmap interface\n"); - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return POLLERR; - buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream); - } else { - dprintk(1,"poll: read() interface\n"); - /* read() capture */ - return videobuf_poll_stream(file, &fh-> vb_vidq, - wait); - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) - return POLLIN|POLLRDNORM; - return 0; + return videobuf_poll_stream(file, q, wait); } static int vivi_release(struct inode *inode, struct file *file) From ba32bd95d431525ad2ffac97cadf9ee40b63939e Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:17 -0300 Subject: [PATCH 280/310] V4L/DVB (6275): V4L: vivi.c remove the "resource" locking The "resource" locking in vivi isn't needed since streamon/streamoff/read_stream do mutual exclusion using q->reading/q->streaming. Plus it is sort of broken: a) res_locked() use in vivi_read() is racey. b) res_free() calls mutex_lock twice causing streamoff to break Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 48 ++++---------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index cdef622f6b32..82755091648b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -170,7 +170,6 @@ struct vivi_dev { int users; /* various device info */ - unsigned int resources; struct video_device vfd; struct vivi_dmaqueue vidq; @@ -726,40 +725,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_release = buffer_release, }; -/* ------------------------------------------------------------------ - IOCTL handling - ------------------------------------------------------------------*/ - - -static int res_get(struct vivi_dev *dev, struct vivi_fh *fh) -{ - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - dev->resources =1; - dprintk(1,"res: get\n"); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_locked(struct vivi_dev *dev) -{ - return (dev->resources); -} - -static void res_free(struct vivi_dev *dev, struct vivi_fh *fh) -{ - mutex_lock(&dev->lock); - dev->resources = 0; - dprintk(1,"res: put\n"); - mutex_lock(&dev->lock); -} - /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ @@ -913,9 +878,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - if (!res_get(dev,fh)) - return -EBUSY; - return (videobuf_streamon(&fh->vb_vidq)); + return videobuf_streamon(&fh->vb_vidq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) @@ -928,10 +891,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - videobuf_streamoff(&fh->vb_vidq); - res_free(dev,fh); - - return (0); + return videobuf_streamoff(&fh->vb_vidq); } static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) @@ -1096,10 +1056,10 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; + struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(fh->dev)) - return -EBUSY; return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } From 00f98d0804c88c29bef81cb98c861f13c9b33f30 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:28 -0300 Subject: [PATCH 281/310] V4L/DVB (6276): V4L: videobuf-core.c lock before streaming check The reading/streaming fields are used for mutual exclusion of the queue and should be protected by the queue lock. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index a27e114cacef..ca67f80184bd 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -289,16 +289,18 @@ int videobuf_reqbufs(struct videobuf_queue *q, return -EINVAL; } + mutex_lock(&q->lock); if (q->streaming) { dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } if (!list_empty(&q->stream)) { dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } - mutex_lock(&q->lock); count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; From 14f37aee299bf9a897516f5e33948ee1f014eae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 21:00:50 -0300 Subject: [PATCH 282/310] V4L/DVB (6277): vivi cleanup: remove the unused vars Vivi driver is now simpler. This patch removes the now unused vars. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 82755091648b..61a6608d6e61 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -871,7 +871,6 @@ static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -884,7 +883,6 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1056,8 +1054,6 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; - struct vivi_dev *dev = fh->dev; - struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, @@ -1070,7 +1066,6 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; - struct vivi_buffer *buf; struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); From d00cd2985e0e796621adf0f782af1563d990b0b5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Tue, 2 Oct 2007 09:03:39 -0300 Subject: [PATCH 283/310] V4L/DVB (6278): Buf: fix typo that caused data loss when readng streams from device If videobuf_read_stream reads two or more buffers it was overwriting the first one Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index ca67f80184bd..8e4026e6fae3 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -771,7 +771,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } if (q->read_buf->state == STATE_DONE) { - rc = CALL (q,copy_stream, q, data, count, + rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; From 9320874a3e6aea7044a4a7eedeab13db990424ab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 3 Oct 2007 11:23:01 -0300 Subject: [PATCH 284/310] V4L/DVB (6279): en_50221: convert to kthread API Here's an attempted update to the full kthread API + wake_up_process: Signed-off-by: Andrew Morton CC: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 84 ++++----------------- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 5c7bcb8393d2..084a508a03da 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" @@ -139,13 +140,7 @@ struct dvb_ca_private { wait_queue_head_t wait_queue; /* PID of the monitoring thread */ - pid_t thread_pid; - - /* Wait queue used when shutting thread down */ - wait_queue_head_t thread_queue; - - /* Flag indicating when thread should exit */ - unsigned int exit:1; + struct task_struct *thread; /* Flag indicating if the CA device is open */ unsigned int open:1; @@ -901,27 +896,9 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) ca->wakeup = 1; mb(); - wake_up_interruptible(&ca->thread_queue); + wake_up_process(ca->thread); } -/** - * Used by the CA thread to determine if an early wakeup is necessary - * - * @param ca CA instance. - */ -static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca) -{ - if (ca->wakeup) { - ca->wakeup = 0; - return 1; - } - if (ca->exit) - return 1; - - return 0; -} - - /** * Update the delay used by the thread. * @@ -981,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) static int dvb_ca_en50221_thread(void *data) { struct dvb_ca_private *ca = data; - char name[15]; int slot; int flags; int status; @@ -990,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data) dprintk("%s\n", __FUNCTION__); - /* setup kernel thread */ - snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - /* choose the correct initial delay */ dvb_ca_en50221_thread_update_delay(ca); /* main loop */ - while (!ca->exit) { + while (!kthread_should_stop()) { /* sleep for a bit */ - if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, - dvb_ca_en50221_thread_should_wakeup(ca), - ca->delay); - if ((flags == -ERESTARTSYS) || ca->exit) { - /* got signal or quitting */ - break; - } + while (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; } ca->wakeup = 0; @@ -1180,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data) } } - /* completed */ - ca->thread_pid = 0; - mb(); - wake_up_interruptible(&ca->thread_queue); return 0; } @@ -1683,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, goto error; } init_waitqueue_head(&ca->wait_queue); - ca->thread_pid = 0; - init_waitqueue_head(&ca->thread_queue); - ca->exit = 0; ca->open = 0; ca->wakeup = 0; ca->next_read_slot = 0; @@ -1711,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, mb(); /* create a kthread for monitoring this CA device */ - - ret = kernel_thread(dvb_ca_en50221_thread, ca, 0); - - if (ret < 0) { - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); + ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", + ca->dvbdev->adapter->num, ca->dvbdev->id); + if (IS_ERR(ca->thread)) { + ret = PTR_ERR(ca->thread); + printk("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); goto error; } - ca->thread_pid = ret; return 0; error: @@ -1749,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) dprintk("%s\n", __FUNCTION__); /* shutdown the thread if there was one */ - if (ca->thread_pid) { - if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", - ca->dvbdev->adapter->num, ca->thread_pid); - } else { - ca->exit = 1; - mb(); - dvb_ca_en50221_thread_wakeup(ca); - wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0); - } - } + kthread_stop(ca->thread); for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); From 5a3ebe8755e88cd765f75121665c0d38004f8f37 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 04:54:11 -0300 Subject: [PATCH 285/310] V4L/DVB (6283): videobuf: Remove references to old Kconfig option name CONFIG_VIDEO_BUF_DVB became CONFIG_VIDEOBUF_DVB. But in these cases, it makes more sense to use CONFIG_VIDEO_SAA7134_DVB or CONFIG_VIDEO_CX88_DVB_MODULE depending on the driver. The reference in cx23885.h should just be removed, as the code there needs to be included if DVB is on or off. I do not think you can even compile the cx23885 driver without DVB. It's clearly just leftover from when the file was obvious copied from the cx88 driver (which is not mentioned in the copyright BTW). Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885.h | 2 -- drivers/media/video/cx88/cx88-i2c.c | 2 +- drivers/media/video/cx88/cx88.h | 6 +++--- drivers/media/video/saa7134/saa7134.h | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 45c47cd60703..3d4fae565e35 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,9 +28,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include -#endif #include "btcx-risc.h" #include "cx23885-reg.h" diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6ae21750b2c1..c8b1c50625f4 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -145,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) if (0 != core->i2c_rc) return; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) { if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl) core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index b3fe2d59cd13..42e0a9b8c550 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -31,7 +31,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) #include #endif @@ -311,7 +311,7 @@ struct cx88_core { unsigned int tuner_formats; /* config info -- dvb */ -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); #endif @@ -458,7 +458,7 @@ struct cx8802_dev { int width; int height; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) /* for dvb only */ struct videobuf_dvb dvb; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 745b750cd3fe..064f3dbe6951 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -41,7 +41,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) #include #endif @@ -538,7 +538,7 @@ struct saa7134_dev { struct work_struct empress_workqueue; int empress_started; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) /* SAA7134_MPEG_DVB only */ struct videobuf_dvb dvb; int (*original_demod_sleep)(struct dvb_frontend* fe); From 409d84f85a8d523ecd108cbe2c0e722682da95ff Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 05:28:45 -0300 Subject: [PATCH 286/310] V4L/DVB (6284): cx23885: Update to new videobuf code cx23885 was still uses the old video-buf includes and code, which would only `work' if one happened to be compiling against a kernel that had the old headers. Even then, it wouldn't actually work, it would just compile without errors. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++++---- drivers/media/video/cx23885/cx23885.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 51879961e3ea..4d0614093ad6 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1008,10 +1008,12 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb, 0, 0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } @@ -1176,8 +1178,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + videobuf_to_dma(&buf->vb)->sglist, + buf->vb.width, buf->vb.height); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 3d4fae565e35..dec4dc2fcbb4 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include "btcx-risc.h" #include "cx23885-reg.h" From 925343ecdfd3f1dafd1049ddd4944621bbe3422e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 23 Aug 2007 21:22:15 -0300 Subject: [PATCH 287/310] V4L/DVB (6285): Remove pointless kmalloc() return value cast in Zoran PCI controller driver No need to cast the void pointer returned by kmalloc() in drivers/media/video/zoran_driver.c::v4l_fbuffer_alloc(). Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index d831ca16d9e9..1c14fa2bd411 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -339,10 +339,7 @@ v4l_fbuffer_alloc (struct file *file) if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) { /* Use kmalloc */ - mem = - (unsigned char *) kmalloc(fh->v4l_buffers. - buffer_size, - GFP_KERNEL); + mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR From 593f18c6e4d04134f240fbad001d878802d8925f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Oct 2007 02:17:09 -0300 Subject: [PATCH 288/310] V4L/DVB (6286): Add support for MSI TV @nywhere A/D NB This is a Lifeview hybrid OEM board. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 831b4da48b80..67f08cc4be70 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -92,7 +92,7 @@ 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] - 94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502] + 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,4e42:3502] 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138] 96 -> Medion Md8800 Quadro [16be:0007,16be:0008] 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6b6eae82bcfc..62420d599d75 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2898,7 +2898,7 @@ struct saa7134_board saa7134_boards[] = { .radio_addr = ADDR_UNSET, }, [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = { - .name = "LifeView FlyDVB-T Hybrid Cardbus", + .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -4280,6 +4280,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x3502, + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, From aecfde539eeac11f269894413abf3b60cf74844f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 09:04:09 -0300 Subject: [PATCH 289/310] V4L/DVB (6287): Fix DMA Scatter/Gather constructor cx23885 driver were converted to use the newer videobuf support. Unfortunately, the constructor weren't changed. This causes an oops, since the abstract methods (implemented as callbacks) aren't defined. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Michael Krufky --- drivers/media/video/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index d952f3a67532..eda8c05d0931 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -186,7 +186,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx23885_buffer), port); err = dvb_register(port); From 7568e3ce6710cb2c1bc1564a273e9f222efbc95e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 8 Oct 2007 09:20:49 -0300 Subject: [PATCH 290/310] V4L/DVB (6289): Remove reference to dead CONFIG_UST and ust.h header Signed-off-by: Robert P. J. Day Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 0689a041d777..c3440b280d20 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -65,11 +65,6 @@ #include #endif -#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE) -#include -#endif - - #include MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); From 5ddff43435394c1c2540fcdeed00cb54862c31bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:43:49 -0300 Subject: [PATCH 291/310] V4L/DVB (6290): remove videobuf_set_pci_ops Before the videobuf redesign, a procedure for re-using videobuf without PCI scatter/gather where provided by changing the pci-dependent operations by other operations. With the newer approach, those methods are obsolete and can safelly be removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 62 ++------------------------- include/media/videobuf-core.h | 3 -- include/media/videobuf-dma-sg.h | 19 -------- 3 files changed, 4 insertions(+), 80 deletions(-) diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 05dd38343fa3..a38efe10feb4 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -220,7 +220,6 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); @@ -247,10 +246,8 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) return -ENOMEM; } if (!dma->bus_addr) { - if (ops && ops->vb_map_sg) { - dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->sglen = pci_map_sg(dev,dma->sglist, dma->nr_pages, dma->direction); - } if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__FUNCTION__); @@ -266,30 +263,24 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(!dma->sglen); - if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - + pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); if (!dma->sglen) return 0; - if (!dma->bus_addr && ops && ops->vb_unmap_sg) - ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction); + kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; @@ -325,12 +316,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_map(&q,dma)); } @@ -338,12 +325,8 @@ int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_unmap(&q,dma)); } @@ -712,46 +695,10 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - struct videobuf_dma_sg_ops *priv_ops; - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); q->int_ops=&pci_ops; - - /* FIXME: the code bellow should be removed after having a proper - * memory allocation method for vivi and tm6000 - */ - q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); - BUG_ON (!q->priv_ops); - - priv_ops=q->priv_ops; - - /* Sets default methods for handling Scatter Gather mapping */ - priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; } -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops) -{ - kfree (q->priv_ops); - - q->priv_ops=ops; - - if (!ops) - return; - - /* If not specified, defaults to PCI map sg */ - if (!ops->vb_map_sg) - ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!ops->vb_unmap_sg) - ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - - /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); @@ -771,7 +718,6 @@ EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); EXPORT_SYMBOL_GPL(videobuf_pci_alloc); EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); -EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); /* * Local variables: diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 96949e31eaf8..9bae5a2eda66 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -173,9 +173,6 @@ struct videobuf_queue { /* driver private data */ void *priv_data; - - /*FIXME: should be removed after completing the vb conversion */ - void *priv_ops; }; int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 206d9027b39f..38105031db23 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -89,19 +89,6 @@ struct videbuf_pci_sg_memory struct videobuf_dmabuf dma; }; -/* FIXME: To be removed soon */ -typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, - int direction); - -/* FIXME: To be removed soon */ -struct videobuf_dma_sg_ops -{ - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; - -}; - void videobuf_dma_init(struct videobuf_dmabuf *dma); int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size); @@ -133,9 +120,3 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); -/* FIXME: temporary routine for vivi and tm6000, while lacking implementation - * of videobuf-vmalloc - */ -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops); - From d5f1b01644b6fd5e9eb480a4762cd6b569cb1246 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:48:57 -0300 Subject: [PATCH 292/310] V4L/DVB (6291): Fix: avoid oops on some SMP machines This workaround fix a bug that happens on some SMP machines. On those machines, videobuf_iolock is called too soon, before file .mmap handler. This patch calls the scheduler before iolocking, allowing it to properly call the pending mmap. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 8e4026e6fae3..aa402abc4b0c 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -94,6 +94,14 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, MAGIC_CHECK(vb->magic,MAGIC_BUFFER); MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() + method should be called before _iolock. + On some cases, the mmap_mapper() is called only after scheduling. + + However, this way is just too dirty! Better to wait for some event. + */ + schedule_timeout(HZ); + return CALL(q,iolock,q,vb,fbuf); } From d4cae5a50021271b9ef4e5e39e71e177d12fa8cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 12:20:02 -0300 Subject: [PATCH 293/310] V4L/DVB (6292): videobuf_core init always require callback implementation In the past, videobuf_queue_init were used to initialize PCI DMA videobuffers. This patch renames it, to avoid confusion with the previous kernel API, doing: s/videobuf_queue_init/void videobuf_queue_core_init/ Also, the operations is now part of the function parameter. The function will also add a test if this is defined, otherwise producing BUG. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 23 ++++++++++++++--------- drivers/media/video/videobuf-dma-sg.c | 4 ++-- drivers/media/video/videobuf-vmalloc.c | 4 ++-- include/media/videobuf-core.h | 5 +++-- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index aa402abc4b0c..f5c5ea8b6b08 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -108,23 +108,25 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, /* --------------------------------------------------------------------- */ -void videobuf_queue_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue* q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv) + void *priv, + struct videobuf_qtype_ops *int_ops) { memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; q->priv_data = priv; + q->int_ops = int_ops; /* All buffer operations are mandatory */ BUG_ON (!q->ops->buf_setup); @@ -132,6 +134,9 @@ void videobuf_queue_init(struct videobuf_queue* q, BUG_ON (!q->ops->buf_queue); BUG_ON (!q->ops->buf_release); + /* Having implementations for abstract methods are mandatory */ + BUG_ON (!q->int_ops); + mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); } @@ -966,7 +971,7 @@ EXPORT_SYMBOL_GPL(videobuf_iolock); EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_core_init); EXPORT_SYMBOL_GPL(videobuf_queue_cancel); EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index a38efe10feb4..8bb7fdd306d6 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -695,8 +695,8 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&pci_ops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &pci_ops); } /* --------------------------------------------------------------------- */ diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index c9d6ae0d3b49..2e3689a12a28 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -333,8 +333,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&qops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &qops); } EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9bae5a2eda66..9fa09fb800a1 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -181,14 +181,15 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, void *videobuf_alloc(struct videobuf_queue* q); -void videobuf_queue_init(struct videobuf_queue *q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv); + void *priv, + struct videobuf_qtype_ops *int_ops); int videobuf_queue_is_busy(struct videobuf_queue *q); void videobuf_queue_cancel(struct videobuf_queue *q); From 54bd5b66c87d14e250f108aad1228b905d6882f6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 8 Oct 2007 16:26:13 -0300 Subject: [PATCH 294/310] V4L/DVB (6293): V4L: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a patch that converts all users in drivers/media/video/ to struct device. Reviewed-by: Thierry Merle Reviewed-by: Mike Isely Reviewed-by: Luca Risolia Signed-off-by: Kay Sievers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 11 +- drivers/media/video/et61x251/et61x251_core.c | 58 ++--- drivers/media/video/ov511.c | 81 ++++--- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 210 ++++++++++-------- drivers/media/video/pwc/pwc-if.c | 31 +-- drivers/media/video/sn9c102/sn9c102_core.c | 112 +++++----- drivers/media/video/stv680.c | 51 ++--- .../media/video/usbvision/usbvision-video.c | 119 +++++----- drivers/media/video/videodev.c | 40 ++-- include/media/v4l2-dev.h | 14 +- 10 files changed, 387 insertions(+), 340 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 4ab4e14b5c64..49278537eec4 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -154,13 +154,14 @@ MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* sysfs */ -static ssize_t show_card(struct class_device *cd, char *buf) +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } -static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ @@ -4615,9 +4616,9 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - if (class_device_create_file(&btv->video_dev->class_dev, - &class_device_attr_card)<0) { - printk(KERN_ERR "bttv%d: class_device_create_file 'card' " + if (device_create_file(&btv->video_dev->class_dev, + &dev_attr_card)<0) { + printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); goto err; } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 31062a981e36..d5fef4c01c87 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -706,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -729,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_reg(struct device* cd, + struct device_attribute *attr, const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -761,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -792,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -830,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -855,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -887,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -923,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -966,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + et61x251_show_reg, et61x251_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + et61x251_show_val, et61x251_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + et61x251_show_i2c_reg, et61x251_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + et61x251_show_i2c_val, et61x251_store_i2c_val); static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index e5edff1059a2..9eb2562347a8 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5554,41 +5554,46 @@ error: * sysfs ***************************************************************************/ -static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) +static inline struct usb_ov511 *cd_to_ov(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_custom_id(struct class_device *cd, char *buf) +static ssize_t show_custom_id(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%d\n", ov->customid); } -static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); +static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", ov->desc); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_bridge(struct class_device *cd, char *buf) +static ssize_t show_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); -static ssize_t show_sensor(struct class_device *cd, char *buf) +static ssize_t show_sensor(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); } -static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); +static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5598,9 +5603,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) sensor_get_brightness(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5610,9 +5616,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) sensor_get_saturation(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5622,9 +5629,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) sensor_get_contrast(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5634,9 +5642,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) sensor_get_hue(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_exposure(struct class_device *cd, char *buf) +static ssize_t show_exposure(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned char exp = 0; @@ -5646,49 +5655,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) sensor_get_exposure(ov, &exp); return sprintf(buf, "%d\n", exp >> 8); } -static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); +static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_custom_id); + rc = video_device_create_file(vdev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &class_device_attr_bridge); + rc = video_device_create_file(vdev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_sensor); + rc = video_device_create_file(vdev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &class_device_attr_brightness); + rc = video_device_create_file(vdev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &class_device_attr_saturation); + rc = video_device_create_file(vdev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &class_device_attr_contrast); + rc = video_device_create_file(vdev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &class_device_attr_hue); + rc = video_device_create_file(vdev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &class_device_attr_exposure); + rc = video_device_create_file(vdev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &class_device_attr_sensor); + video_device_remove_file(vdev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &class_device_attr_bridge); + video_device_remove_file(vdev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &class_device_attr_custom_id); + video_device_remove_file(vdev, &dev_attr_custom_id); err: return rc; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7ab79baa1c8c..b20dc4421d59 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -33,16 +33,16 @@ struct pvr2_sysfs { struct pvr2_channel channel; - struct class_device *class_dev; + struct device *class_dev; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc *debugifc; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item *item_first; struct pvr2_sysfs_ctl_item *item_last; - struct class_device_attribute attr_v4l_minor_number; - struct class_device_attribute attr_v4l_radio_minor_number; - struct class_device_attribute attr_unit_number; - struct class_device_attribute attr_bus_info; + struct device_attribute attr_v4l_minor_number; + struct device_attribute attr_v4l_radio_minor_number; + struct device_attribute attr_unit_number; + struct device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; @@ -51,22 +51,22 @@ struct pvr2_sysfs { #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc { - struct class_device_attribute attr_debugcmd; - struct class_device_attribute attr_debuginfo; + struct device_attribute attr_debugcmd; + struct device_attribute attr_debuginfo; int debugcmd_created_ok; int debuginfo_created_ok; }; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item { - struct class_device_attribute attr_name; - struct class_device_attribute attr_type; - struct class_device_attribute attr_min; - struct class_device_attribute attr_max; - struct class_device_attribute attr_enum; - struct class_device_attribute attr_bits; - struct class_device_attribute attr_val; - struct class_device_attribute attr_custom; + struct device_attribute attr_name; + struct device_attribute attr_type; + struct device_attribute attr_min; + struct device_attribute attr_max; + struct device_attribute attr_enum; + struct device_attribute attr_bits; + struct device_attribute attr_val; + struct device_attribute attr_custom; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; @@ -80,13 +80,13 @@ struct pvr2_sysfs_class { struct class class; }; -static ssize_t show_name(int id,struct class_device *class_dev,char *buf) +static ssize_t show_name(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_type(int id,struct class_device *class_dev,char *buf) +static ssize_t show_type(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; enum pvr2_ctl_type tp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_min(int id,struct class_device *class_dev,char *buf) +static ssize_t show_min(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_max(int id,struct class_device *class_dev,char *buf) +static ssize_t show_max(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) +static ssize_t show_enum(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; unsigned int bcnt,ccnt,ecnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) return bcnt; } -static ssize_t show_bits(int id,struct class_device *class_dev,char *buf) +static ssize_t show_bits(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int valid_bits,msk; unsigned int bcnt,ccnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, return ret; } -static ssize_t store_val_norm(int id,struct class_device *class_dev, +static ssize_t store_val_norm(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,0,sfp,buf,count); if (!ret) ret = count; return ret; } -static ssize_t store_val_custom(int id,struct class_device *class_dev, +static ssize_t store_val_custom(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,1,sfp,buf,count); if (!ret) ret = count; return ret; @@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, Mike Isely 30-April-2005 This next batch of horrible preprocessor hackery is needed because the - kernel's class_device_attribute mechanism fails to pass the actual + kernel's device_attribute mechanism fails to pass the actual attribute through to the show / store functions, which means we have no way to package up any attribute-specific parameters, like for example the control id. So we work around this brain-damage by encoding the control @@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, */ #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, char *buf) \ { return sf_name(ctl_id,class_dev,buf); } #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, const char *buf, size_t count) \ { return sf_name(ctl_id,class_dev,buf,count); } #define CREATE_BATCH(ctl_id) \ @@ -395,17 +397,27 @@ CREATE_BATCH(58) CREATE_BATCH(59) struct pvr2_sysfs_func_set { - ssize_t (*show_name)(struct class_device *,char *); - ssize_t (*show_type)(struct class_device *,char *); - ssize_t (*show_min)(struct class_device *,char *); - ssize_t (*show_max)(struct class_device *,char *); - ssize_t (*show_enum)(struct class_device *,char *); - ssize_t (*show_bits)(struct class_device *,char *); - ssize_t (*show_val_norm)(struct class_device *,char *); - ssize_t (*store_val_norm)(struct class_device *, + ssize_t (*show_name)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_type)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_min)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_max)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_enum)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_bits)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_val_norm)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_norm)(struct device *, + struct device_attribute *attr, const char *,size_t); - ssize_t (*show_val_custom)(struct class_device *,char *); - ssize_t (*store_val_custom)(struct class_device *, + ssize_t (*show_val_custom)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_custom)(struct device *, + struct device_attribute *attr, const char *,size_t); }; @@ -597,9 +609,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *,char *); -static ssize_t debugcmd_show(struct class_device *,char *); -static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *,char *); +static ssize_t debugcmd_show(struct device *,char *); +static ssize_t debugcmd_store(struct device *,const char *,size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -616,16 +628,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.attr.mode = S_IRUGO; dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; - ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); + ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debugcmd_created_ok = !0; } - ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debuginfo_created_ok = !0; @@ -637,11 +649,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) { if (!sfp->debugifc) return; if (sfp->debugifc->debuginfo_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debuginfo); } if (sfp->debugifc->debugcmd_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debugcmd); } kfree(sfp->debugifc); @@ -683,7 +695,7 @@ static void pvr2_sysfs_class_release(struct class *class) } -static void pvr2_sysfs_release(struct class_device *class_dev) +static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); kfree(class_dev); @@ -698,32 +710,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); if (sfp->bus_info_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_bus_info); } if (sfp->v4l_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_minor_number); } if (sfp->v4l_radio_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); } if (sfp->unit_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->class_data = NULL; - class_device_unregister(sfp->class_dev); + sfp->class_dev->driver_data = NULL; + device_unregister(sfp->class_dev); sfp->class_dev = NULL; } -static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) +static ssize_t v4l_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -731,21 +744,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) } -static ssize_t bus_info_show(struct class_device *class_dev,char *buf) +static ssize_t bus_info_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); } -static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, +static ssize_t v4l_radio_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -753,10 +768,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, } -static ssize_t unit_number_show(struct class_device *class_dev,char *buf) +static ssize_t unit_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -767,7 +783,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, struct pvr2_sysfs_class *class_ptr) { struct usb_device *usb_dev; - struct class_device *class_dev; + struct device *class_dev; int ret; usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); @@ -779,23 +795,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->class = &class_ptr->class; if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", pvr2_hdw_get_sn(sfp->channel.hdw)); } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); } else { kfree(class_dev); return; } - class_dev->dev = &usb_dev->dev; + class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->class_data = sfp; - ret = class_device_register(class_dev); + class_dev->driver_data = sfp; + ret = device_register(class_dev); if (ret) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); kfree(class_dev); return; @@ -805,10 +821,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_minor_number_created_ok = !0; @@ -818,10 +834,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; sfp->attr_v4l_radio_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_radio_minor_number_created_ok = !0; @@ -831,9 +847,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_unit_number.attr.mode = S_IRUGO; sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; - ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->unit_number_created_ok = !0; @@ -843,10 +859,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_bus_info.attr.mode = S_IRUGO; sfp->attr_bus_info.show = bus_info_show; sfp->attr_bus_info.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_bus_info); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->bus_info_created_ok = !0; @@ -886,7 +902,7 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, +static int pvr2_sysfs_hotplug(struct device *cd,char **envp, int numenvp,char *buf,int size) { /* Even though we don't do anything here, we still need this function @@ -902,8 +918,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; - clp->class.release = pvr2_sysfs_release; - clp->class.uevent = pvr2_sysfs_hotplug; + clp->class.dev_release = pvr2_sysfs_release; + clp->class.dev_uevent = pvr2_sysfs_hotplug; if (class_register(&clp->class)) { pvr2_sysfs_trace( "Registration failed for pvr2_sysfs_class id=%p",clp); @@ -921,32 +937,32 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_store(struct class_device *class_dev, - const char *buf,size_t count) +static ssize_t debugcmd_store(struct device *class_dev, + const char *buf, size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 0ff5718bf9b9..0b67d4ec0318 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -996,20 +996,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f /********* * sysfs *********/ -static struct pwc_device *cd_to_pwc(struct class_device *cd) +static struct pwc_device *cd_to_pwc(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf) +static ssize_t show_pan_tilt(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); } -static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) +static ssize_t store_pan_tilt(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct pwc_device *pdev = cd_to_pwc(class_dev); int pan, tilt; @@ -1025,10 +1027,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, return ret; return strlen(buf); } -static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); +static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, + store_pan_tilt); -static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf) +static ssize_t show_snapshot_button_status(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); int status = pdev->snapshot_button_status; @@ -1036,26 +1039,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char return sprintf(buf, "%d\n", status); } -static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); +static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, + NULL); static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &class_device_attr_button); + rc = video_device_create_file(vdev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + rc = video_device_create_file(vdev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_button); err: return rc; } @@ -1064,8 +1067,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &class_device_attr_pan_tilt); - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_pan_tilt); + video_device_remove_file(vdev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index e0accf1b8713..6991e06f7651 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1029,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1053,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1086,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1118,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1157,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1183,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1216,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1253,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1298,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_green(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; enum sn9c102_bridge bridge; @@ -1329,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) case BRIDGE_SN9C102: if (value > 0x0f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; case BRIDGE_SN9C103: case BRIDGE_SN9C105: case BRIDGE_SN9C120: if (value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; } @@ -1347,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_blue(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1357,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } static ssize_t -sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_red(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1375,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } -static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_frame_header(struct device* cd, + struct device_attribute *attr, + char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1401,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - sn9c102_show_reg, sn9c102_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - sn9c102_show_val, sn9c102_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); -static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, - sn9c102_show_frame_header, NULL); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_val, sn9c102_store_i2c_val); +static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); +static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); +static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); +static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; - if ((err = class_device_create_file(classdev, - &class_device_attr_frame_header))) + if ((err = device_create_file(classdev, &dev_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_frame_header; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = class_device_create_file(classdev, - &class_device_attr_green))) + if ((err = device_create_file(classdev, &dev_attr_green))) goto err_i2c_val; } else { - if ((err = class_device_create_file(classdev, - &class_device_attr_blue))) + if ((err = device_create_file(classdev, &dev_attr_blue))) goto err_i2c_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_red))) + if ((err = device_create_file(classdev, &dev_attr_red))) goto err_blue; } return 0; err_blue: - class_device_remove_file(classdev, &class_device_attr_blue); + device_remove_file(classdev, &dev_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_val); + device_remove_file(classdev, &dev_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_frame_header: - class_device_remove_file(classdev, &class_device_attr_frame_header); + device_remove_file(classdev, &dev_attr_frame_header); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 4dc5bc714b95..9e009a7ab863 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -499,13 +499,14 @@ exit: * sysfs ***************************************************************************/ #define stv680_file(name, variable, field) \ -static ssize_t show_##name(struct class_device *class_dev, char *buf) \ +static ssize_t show_##name(struct device *class_dev, \ + struct device_attribute *attr, char *buf) \ { \ struct video_device *vdev = to_video_device(class_dev); \ struct usb_stv *stv = video_get_drvdata(vdev); \ return sprintf(buf, field, stv->variable); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); stv680_file(model, camera_name, "%s\n"); stv680_file(in_use, user, "%d\n"); @@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_in_use); + rc = video_device_create_file(vdev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_streaming); + rc = video_device_create_file(vdev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &class_device_attr_palette); + rc = video_device_create_file(vdev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &class_device_attr_frames_total); + rc = video_device_create_file(vdev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &class_device_attr_frames_read); + rc = video_device_create_file(vdev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + rc = video_device_create_file(vdev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + rc = video_device_create_file(vdev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &class_device_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &class_device_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &class_device_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &class_device_attr_palette); + video_device_remove_file(vdev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &class_device_attr_in_use); + video_device_remove_file(vdev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err: return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_in_use); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_palette); - video_device_remove_file(vdev, &class_device_attr_frames_total); - video_device_remove_file(vdev, &class_device_attr_frames_read); - video_device_remove_file(vdev, &class_device_attr_packets_dropped); - video_device_remove_file(vdev, &class_device_attr_decoding_errors); + video_device_remove_file(vdev, &dev_attr_model); + video_device_remove_file(vdev, &dev_attr_in_use); + video_device_remove_file(vdev, &dev_attr_streaming); + video_device_remove_file(vdev, &dev_attr_palette); + video_device_remove_file(vdev, &dev_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_decoding_errors); } /******************************************************************** diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 2f9b2b9e3b09..e2f3c01cfa13 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -182,20 +182,22 @@ MODULE_ALIAS(DRIVER_ALIAS); #define YES_NO(x) ((x) ? "Yes" : "No") -static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } -static ssize_t show_version(struct class_device *cd, char *buf) +static ssize_t show_version(struct device *cd, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); } -static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); +static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -203,9 +205,10 @@ static ssize_t show_model(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -217,9 +220,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -231,9 +235,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -245,9 +250,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -259,9 +265,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_streaming(struct class_device *cd, char *buf) +static ssize_t show_streaming(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -269,9 +276,10 @@ static ssize_t show_streaming(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } -static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); +static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); -static ssize_t show_compression(struct class_device *cd, char *buf) +static ssize_t show_compression(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -279,16 +287,17 @@ static ssize_t show_compression(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } -static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); +static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); -static ssize_t show_device_bridge(struct class_device *cd, char *buf) +static ssize_t show_device_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { @@ -296,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev) if (!vdev) return; do { - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_version); + res = device_create_file(&vdev->class_dev, + &dev_attr_version); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_model); + res = device_create_file(&vdev->class_dev, + &dev_attr_model); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_hue); + res = device_create_file(&vdev->class_dev, + &dev_attr_hue); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_contrast); + res = device_create_file(&vdev->class_dev, + &dev_attr_contrast); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_brightness); + res = device_create_file(&vdev->class_dev, + &dev_attr_brightness); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_saturation); + res = device_create_file(&vdev->class_dev, + &dev_attr_saturation); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_streaming); + res = device_create_file(&vdev->class_dev, + &dev_attr_streaming); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_compression); + res = device_create_file(&vdev->class_dev, + &dev_attr_compression); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_bridge); + res = device_create_file(&vdev->class_dev, + &dev_attr_bridge); if (res>=0) return; } while (0); @@ -340,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - class_device_remove_file(&vdev->class_dev, - &class_device_attr_version); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_model); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_hue); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_contrast); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_brightness); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_saturation); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_streaming); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_compression); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_bridge); + device_remove_file(&vdev->class_dev, + &dev_attr_version); + device_remove_file(&vdev->class_dev, + &dev_attr_model); + device_remove_file(&vdev->class_dev, + &dev_attr_hue); + device_remove_file(&vdev->class_dev, + &dev_attr_contrast); + device_remove_file(&vdev->class_dev, + &dev_attr_brightness); + device_remove_file(&vdev->class_dev, + &dev_attr_saturation); + device_remove_file(&vdev->class_dev, + &dev_attr_streaming); + device_remove_file(&vdev->class_dev, + &dev_attr_compression); + device_remove_file(&vdev->class_dev, + &dev_attr_bridge); } } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0334b9aaf12a..0fbe8a1a91b3 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -54,15 +54,14 @@ * sysfs stuff */ -static ssize_t show_name(struct class_device *cd, char *buf) +static ssize_t show_name(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); + class_dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - struct video_device *video_device_alloc(void) { struct video_device *vfd; @@ -76,10 +75,9 @@ void video_device_release(struct video_device *vfd) kfree(vfd); } -static void video_release(struct class_device *cd) +static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); #if 1 /* needed until all drivers are fixed */ @@ -89,9 +87,15 @@ static void video_release(struct class_device *cd) vfd->release(vfd); } +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR_NULL +}; + static struct class video_class = { .name = VIDEO_NAME, - .release = video_release, + .dev_attrs = video_device_attrs, + .dev_release = video_release, }; /* @@ -1753,22 +1757,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) - vfd->class_dev.dev = vfd->dev; + vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); - ret = class_device_register(&vfd->class_dev); + sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->class_dev); if (ret < 0) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); goto fail_minor; } - ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); - if (ret < 0) { - printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", - __FUNCTION__); - goto fail_classdev; - } #if 1 /* needed until all drivers are fixed */ @@ -1779,8 +1777,6 @@ int video_register_device(struct video_device *vfd, int type, int nr) #endif return 0; -fail_classdev: - class_device_unregister(&vfd->class_dev); fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; @@ -1804,7 +1800,7 @@ void video_unregister_device(struct video_device *vfd) panic("videodev: bad unregister"); video_device[vfd->minor]=NULL; - class_device_unregister(&vfd->class_dev); + device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 8b79e2cf77fa..e75d5e6c4cea 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -86,8 +86,11 @@ struct video_device /* device ops */ const struct file_operations *fops; + /* sysfs */ + struct device class_dev; /* v4l device */ + struct device *dev; /* device parent */ + /* device info */ - struct device *dev; char name[32]; int type; /* v4l1 */ int type2; /* v4l2 */ @@ -332,7 +335,6 @@ void *priv; /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ struct mutex lock; /* ... helper function uses these */ - struct class_device class_dev; /* sysfs */ }; /* Class-dev to video-device */ @@ -360,18 +362,18 @@ extern int video_usercopy(struct inode *inode, struct file *file, static inline int __must_check video_device_create_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - int ret = class_device_create_file(&vfd->class_dev, attr); + int ret = device_create_file(&vfd->class_dev, attr); if (ret < 0) printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); return ret; } static inline void video_device_remove_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - class_device_remove_file(&vfd->class_dev, attr); + device_remove_file(&vfd->class_dev, attr); } #endif /* CONFIG_VIDEO_V4L1_COMPAT */ From 0ac3a5bbca33840542d98420d9d82e8738299b20 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Oct 2007 16:13:02 -0300 Subject: [PATCH 295/310] V4L/DVB (6295): saa7134: add autodetection for KWorld ATSC-115 Recognize the KWorld ATSC115 PCI ID as a hardware clone of the ATSC110. Signed-off-by: Eric Sandeen Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 67f08cc4be70..a14545300e4c 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -88,7 +88,7 @@ 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421] 88 -> Tevion/KWorld DVB-T 220RF [17de:7201] 89 -> ELSA EX-VISION 700TV [1048:226c] - 90 -> Kworld ATSC110 [17de:7350] + 90 -> Kworld ATSC110/115 [17de:7350,17de:7352] 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 62420d599d75..a4c192fb4e41 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2822,7 +2822,7 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_KWORLD_ATSC110] = { - .name = "Kworld ATSC110", + .name = "Kworld ATSC110/115", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TUV1236D, .radio_type = UNSET, @@ -4082,6 +4082,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x17de, .subdevice = 0x7350, .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ + .subvendor = 0x17de, + .subdevice = 0x7352, + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, From fa3b877e5c75a2f4d1706c40163dbf176a2fd80d Mon Sep 17 00:00:00 2001 From: Joachim Steiger Date: Mon, 8 Oct 2007 20:08:46 -0300 Subject: [PATCH 296/310] V4L/DVB (6296): dib0700: add support for AverMedia DVB-T Express card add Avermedia dvb-t express card 34 (usb2) id Signed-off-by: Joachim Steiger Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 063fb5095bda..e8c4a8694532 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -820,6 +820,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -861,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -886,6 +887,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Leadtek Winfast DTV Dongle (STK7700P based)", { &dib0700_usb_id_table[8], NULL }, { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, } }, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 43bfe50a2227..4fa3e895028a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -121,6 +121,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a From 21a7ad4a7e86a5da16caf61eb50bc92af4929672 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 8 Oct 2007 17:18:17 -0300 Subject: [PATCH 297/310] V4L/DVB (6297): cx23885: remove wrong Kconfig selection of VIDEOBUF fix bad Kconfig dependency of cx23885 module. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index af60700da8c0..72004a07b2d5 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,7 +4,6 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR From 102abd826a20307c5a0d23f49b8a3b5d98bddf94 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:34:11 -0300 Subject: [PATCH 298/310] V4L/DVB (6299): dvb: Add dependencies for VIDEOBUF_DVB It needs to select VIDEOBUF_GEN and VIDEOBUF_DMA_SG, since it uses those modules. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index e705265909da..dd9bd4310c84 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -140,6 +140,8 @@ config VIDEOBUF_VMALLOC config VIDEOBUF_DVB tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG config VIDEO_BTCX tristate From bde00cc027879a39f249ffedb048032cb7e484e4 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:36:21 -0300 Subject: [PATCH 299/310] V4L/DVB (6300): CodingStyle cleanup Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0fbe8a1a91b3..8d8e517b344f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -77,7 +77,8 @@ void video_device_release(struct video_device *vfd) static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, class_dev); + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); #if 1 /* needed until all drivers are fixed */ From c726b65d079cafabc558616badbeead442e2b114 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 19:05:28 -0300 Subject: [PATCH 300/310] V4L/DVB (6301): pvrusb: Update DEBUGIFC sysfs to kernel 2.6.13+ The prototypes for the show and store methods of a device_attribute changed in kernel 2.6.13, but the code in pvrusb2 was never updated. I guess the DEBUGIFC stuff isn't used much.... Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index b20dc4421d59..7a78d6b34738 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -609,9 +609,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *,char *); -static ssize_t debugcmd_show(struct device *,char *); -static ssize_t debugcmd_store(struct device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_store(struct device *, struct device_attribute *, + const char *, size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -937,7 +940,8 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -947,7 +951,8 @@ static ssize_t debuginfo_show(struct device *class_dev,char *buf) } -static ssize_t debugcmd_show(struct device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -957,6 +962,7 @@ static ssize_t debugcmd_show(struct device *class_dev,char *buf) static ssize_t debugcmd_store(struct device *class_dev, + struct device_attribute *attr, const char *buf, size_t count) { struct pvr2_sysfs *sfp; From 49ee718ef51f4d938f80f67207e1bfa2a38897a4 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 5 Oct 2007 16:26:27 -0300 Subject: [PATCH 301/310] V4L/DVB (6305): V4L: videobuf-core.c avoid NULL dereferences in videobuf-core The return value of videobuf_alloc() is unchecked but this function will return NULL on an error. Check for NULL and make videobuf_reqbufs() return the number of successfully allocated buffers. Also, fix saa7146_video.c and bttv-driver.c to use this returned buffer count. Tested against the vivi driver. Not tested against saa7146 or bt8xx devices. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 2 ++ drivers/media/video/bt8xx/bttv-driver.c | 2 ++ drivers/media/video/videobuf-core.c | 20 ++++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 29dbc602a484..f245a3b2ef47 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1212,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int mutex_unlock(&q->lock); return err; } + + gbuffers = err; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 49278537eec4..7a332b3efe51 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3072,6 +3072,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, V4L2_MEMORY_MMAP); if (retval < 0) goto fh_unlock_and_return; + + gbuffers = retval; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index f5c5ea8b6b08..25a98496e3db 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -329,7 +329,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, goto done; } - req->count = count; + req->count = retval; done: mutex_unlock(&q->lock); @@ -698,7 +698,7 @@ int videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags=0; - int count = 0, size = 0; + unsigned int count = 0, size = 0; int err, i; q->ops->buf_setup(q,&count,&size); @@ -709,9 +709,11 @@ int videobuf_read_start(struct videobuf_queue *q) size = PAGE_ALIGN(size); err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) + if (err < 0) return err; + count = err; + for (i = 0; i < count; i++) { field = videobuf_next_field(q); err = q->ops->buf_prepare(q,q->bufs[i],field); @@ -876,6 +878,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q, for (i = 0; i < bcount; i++) { q->bufs[i] = videobuf_alloc(q); + if (q->bufs[i] == NULL) + break; + q->bufs[i]->i = i; q->bufs[i]->input = UNSET; q->bufs[i]->memory = memory; @@ -891,10 +896,13 @@ int videobuf_mmap_setup(struct videobuf_queue *q, } } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); + if (!i) + return -ENOMEM; - return 0; + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + i, bsize); + + return i; } int videobuf_mmap_free(struct videobuf_queue *q) From acd827d63a568a2cfa26ae8e6093b098c91c631b Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 8 Oct 2007 12:07:35 -0300 Subject: [PATCH 302/310] V4L/DVB (6306): Few clenups for saa7134 resume code *Disable DMA explictly on suspend *Enable DMA on resume, after all buffers were configured *Disable overlay on resume - apps should enable it when X is resumed Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 38 ++++++++++--------- drivers/media/video/saa7134/saa7134-tvaudio.c | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index fae0bfe7939f..80f04f252fce 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -398,29 +398,23 @@ void saa7134_buffer_timeout(unsigned long data) int saa7134_buffer_requeue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q) { - struct saa7134_buf *buf , *next; - unsigned long flags; + struct saa7134_buf *buf, *next; - spin_lock_irqsave(&dev->slock, flags); + assert_spin_locked(&dev->slock); buf = q->curr; next = buf; - dprintk("buffer_requeue\n"); - if (!buf) { - spin_unlock_irqrestore(&dev->slock, flags); + if (!buf) return 0; - } dprintk("buffer_requeue : resending active buffers \n"); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, vb.queue); - buf->activate(dev, buf, next); - spin_unlock_irqrestore(&dev->slock, flags); return 0; } @@ -435,6 +429,9 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) assert_spin_locked(&dev->slock); + if (dev->inresume) + return 0; + /* video capture -- dma 0 + video task A */ if (dev->video_q.curr) { task |= 0x01; @@ -1175,13 +1172,15 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { - /* Disable card's IRQs to prevent it from resuming computer */ - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + /* disable overlay - apps should enable it explicitly on resume*/ + dev->ovenable = 0; + + /* Disable interrupts, DMA, and rest of the chip*/ saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - + saa_writel(SAA7134_MAIN_CTRL, 0); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); pci_save_state(pci_dev); @@ -1193,6 +1192,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + unsigned int flags; pci_restore_state(pci_dev); pci_set_power_state(pci_dev, PCI_D0); @@ -1200,6 +1200,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ + dev->inresume = 1; saa7134_board_init1(dev); if (saa7134_boards[dev->board].video_out) @@ -1209,25 +1210,26 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ts_init_hw(dev); saa7134_hw_enable1(dev); - saa7134_set_decoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); - saa7134_board_init2(dev); saa7134_hw_enable2(dev); - dev->force_mute_update = 1; saa7134_tvaudio_setmute(dev); - dev->force_mute_update = 0; saa7134_tvaudio_setvolume(dev, dev->ctl_volume); saa7134_enable_i2s(dev); - /*recapture unfinished buffer(s)*/ + /*resume unfinished buffer(s)*/ + spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); saa7134_buffer_requeue(dev, &dev->vbi_q); saa7134_buffer_requeue(dev, &dev->ts_q); + /* start DMA now*/ + dev->inresume = 0; + saa7134_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock, flags); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index df2dab06387d..1b9e39a5ea47 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in && !dev->force_mute_update) { + dev->hw_input == in && !dev->inresume) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 064f3dbe6951..28ec6804bd5d 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,9 +522,9 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; - unsigned int force_mute_update; int last_carrier; int nosignal; + unsigned int inresume; /* SAA7134_MPEG_* */ struct saa7134_ts ts; From 3abff557d5eed7d6fd03aa11353a1c0f329cac2b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:03:12 -0300 Subject: [PATCH 303/310] V4L/DVB (6307): V4L: w9968cf, remove bad usage of ERESTARTSYS w9968cf, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/w9968cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 77599f228b61..5a1b5f5a7d46 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -2679,7 +2679,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) /* This the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&w9968cf_disconnect)) - return -ERESTARTSYS; + return -EAGAIN; cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); From c3e2a8e64cb2282a406ff6e63f7bd09eb6f61a1d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:15:27 -0300 Subject: [PATCH 304/310] V4L/DVB (6308): V4L: zc0301, remove bad usage of ERESTARTSYS zc0301, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zc0301/zc0301_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 35138c594be1..08a93c31c0a0 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -655,7 +655,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) int err = 0; if (!down_read_trylock(&zc0301_dev_lock)) - return -ERESTARTSYS; + return -EAGAIN; cam = video_get_drvdata(video_devdata(filp)); From 7948261942ffdb35e274b8e1a0889601f45d4603 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:39 -0300 Subject: [PATCH 305/310] V4L/DVB (6311): dvb: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_demux.c | 5 +---- drivers/media/dvb/dvb-core/dvbdev.c | 27 ++++++++------------------ 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index cb6987fce26c..7959020f9317 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; - list_for_each(pos, head) { - feed = list_entry(pos, struct dvb_demux_feed, list_head); - + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 6b7954daeb4a..56231d8edc07 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -58,18 +58,13 @@ static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { - struct list_head *entry; + struct dvb_adapter *adap; - list_for_each (entry, &dvb_adapter_list) { - struct list_head *entry0; - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); - list_for_each (entry0, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry0, struct dvb_device, list_head); + list_for_each_entry(adap, &dvb_adapter_list, list_head) { + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (nums2minor(adap->num, dev->type, dev->id) == minor) return dev; - } } return NULL; @@ -179,13 +174,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) u32 id = 0; while (id < DVB_MAX_IDS) { - struct list_head *entry; - list_for_each (entry, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry, struct dvb_device, list_head); + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; - } return id; skip: id++; @@ -279,13 +271,10 @@ static int dvbdev_get_free_adapter_num (void) int num = 0; while (num < DVB_MAX_ADAPTERS) { - struct list_head *entry; - list_for_each (entry, &dvb_adapter_list) { - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); + struct dvb_adapter *adap; + list_for_each_entry(adap, &dvb_adapter_list, list_head) if (adap->num == num) goto skip; - } return num; skip: num++; From 8bb629e22f2547736c24fe4738673e20cc06d469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:40 -0300 Subject: [PATCH 306/310] V4L/DVB (6312): cx88: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 4 +--- drivers/media/video/cx88/cx88-vbi.c | 5 +---- drivers/media/video/cx88/cx88-video.c | 11 +++-------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 85609b41f86e..62e8dd24c5f5 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1013,11 +1013,9 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; - struct list_head *item; mutex_lock(&devlist); - list_for_each(item,&cx88_devlist) { - core = list_entry(item, struct cx88_core, devlist); + list_for_each_entry(core, &cx88_devlist, devlist) { if (pci->bus->number != core->pci_bus) continue; if (PCI_SLOT(pci->devfn) != core->pci_slot) diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index aa40505c4b3a..babb08556406 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -99,7 +99,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { struct cx88_buffer *buf; - struct list_head *item; if (list_empty(&q->active)) return 0; @@ -108,10 +107,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx8800_start_vbi_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 1439b7268532..231ae6c4dd22 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -466,17 +466,14 @@ static int restart_video_queue(struct cx8800_dev *dev, { struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; - struct list_head *item; if (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); start_video_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); - buf->count = q->count++; - } + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } @@ -713,12 +710,10 @@ static int video_open(struct inode *inode, struct file *file) struct cx8800_dev *h,*dev = NULL; struct cx88_core *core; struct cx8800_fh *fh; - struct list_head *list; enum v4l2_buf_type type = 0; int radio = 0; - list_for_each(list,&cx8800_devlist) { - h = list_entry(list, struct cx8800_dev, devlist); + list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; From 805a43924158e4eb2bffc4cac0aedcfb42a89469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:41 -0300 Subject: [PATCH 307/310] V4L/DVB (6313): ivtv: Replace list_for_each+list_entry with list_for_each_entry Also fixed a few cases of cut&paste errors where 'buf' would be set to the first entry in the list prior to be used as the loop iterator. In one case the value of buf was used before it was changed, but the rest were unnecessary. There was one list_for_each+list_entry loop that wasn't changed, since it depending on the loop iterator being left as NULL if the list was empty. Signed-off-by: Trent Piepho CC: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index bf7d99c6ffaf..fd1688e4757d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -42,7 +42,6 @@ static void ivtv_pio_work_handler(struct ivtv *itv) { struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; struct ivtv_buffer *buf; - struct list_head *p; int i = 0; IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); @@ -54,9 +53,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) return; } IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); - buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_dma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + list_for_each_entry(buf, &s->q_dma.list, list) { u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ @@ -97,7 +94,6 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 bytes_needed = 0; u32 offset, size; u32 UVoffset = 0, UVsize = 0; @@ -202,9 +198,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { if (skip_bufs-- > 0) continue; s->sg_pending[idx].dst = buf->dma_handle; @@ -289,9 +283,7 @@ static void dma_post(struct ivtv_stream *s) if (buf) buf->bytesused += s->dma_last_offset; if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_dma.list, list) { /* Parse and Groom VBI Data */ s->q_dma.bytesused -= buf->bytesused; ivtv_process_vbi_data(itv, buf, 0, s->type); @@ -311,7 +303,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 y_size = itv->params.height * itv->params.width; u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; @@ -320,10 +311,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { offset = uv_offset; @@ -677,11 +665,9 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) we just drop the old requests when there are already three requests queued. */ if (s->sg_pending_size > 2) { - struct list_head *p; - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + struct ivtv_buffer *buf; + list_for_each_entry(buf, &s->q_predma.list, list) ivtv_buf_sync_for_cpu(s, buf); - } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); s->sg_pending_size = 0; } From 6d28e98906aa9405895f92348543d08da1837ea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: [PATCH 308/310] V4L/DVB (6314): saa7134: Replace list_for_each+list_entry with list_for_each_entry A couple loops weren't changed because they expected the loop iterator to be left as NULL if the list was empty. Maybe the code should just check for that first, then loop? Adjust some of the loop logic to be simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 20 ++------- drivers/media/video/saa7134/saa7134-empress.c | 15 +++---- drivers/media/video/saa7134/saa7134-oss.c | 42 +++++++------------ drivers/media/video/saa7134/saa7134-video.c | 22 +++++----- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80f04f252fce..1a4a24471f20 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -890,7 +890,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct saa7134_dev *dev; - struct list_head *item; struct saa7134_mpeg_ops *mops; int err; @@ -1072,10 +1071,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_devcount++; mutex_lock(&devlist_lock); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_attach(mops, dev); - } list_add_tail(&dev->devlist,&saa7134_devlist); mutex_unlock(&devlist_lock); @@ -1109,7 +1106,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); - struct list_head *item; struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ @@ -1138,10 +1134,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) /* unregister */ mutex_lock(&devlist_lock); list_del(&dev->devlist); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_detach(mops, dev); - } mutex_unlock(&devlist_lock); saa7134_devcount--; @@ -1237,14 +1231,11 @@ static int saa7134_resume(struct pci_dev *pci_dev) int saa7134_ts_register(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_attach(ops, dev); - } list_add_tail(&ops->next,&mops_list); mutex_unlock(&devlist_lock); return 0; @@ -1252,15 +1243,12 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); list_del(&ops->next); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_detach(ops, dev); - } mutex_unlock(&devlist_lock); } diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index a16df57af63a..34ca874dd7fe 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -76,17 +76,14 @@ static int ts_init_encoder(struct saa7134_dev* dev) static int ts_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->empress_dev && h->empress_dev->minor == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->empress_dev && dev->empress_dev->minor == minor) + goto found; + return -ENODEV; + found: dprintk("open minor=%d\n",minor); err = -EBUSY; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 1a737b647366..aedf04653e0e 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -239,17 +239,14 @@ static int dsp_rec_stop(struct saa7134_dev *dev) static int dsp_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_dsp == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_dsp == minor) + goto found; + return -ENODEV; + found: mutex_lock(&dev->dmasound.lock); err = -EBUSY; @@ -680,19 +677,14 @@ mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) static int mixer_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_mixer == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; - - file->private_data = dev; - return 0; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_mixer == minor) { + file->private_data = dev; + return 0; + } + return -ENODEV; } static int mixer_release(struct inode *inode, struct file *file) @@ -1022,18 +1014,14 @@ static int saa7134_oss_init(void) static void saa7134_oss_exit(void) { - struct saa7134_dev *dev = NULL; - struct list_head *list; - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); + struct saa7134_dev *dev; + list_for_each_entry(dev, &saa7134_devlist, devlist) { /* Device isn't registered by OSS, probably ALSA's */ if (!dev->dmasound.minor_dsp) continue; oss_device_exit(dev); - } saa7134_dmasound_init = NULL; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 7c97ac15e665..471b92793c12 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1285,26 +1285,24 @@ static int saa7134_resource(struct saa7134_fh *fh) static int video_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; + struct saa7134_dev *dev; struct saa7134_fh *fh; - struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->video_dev && (h->video_dev->minor == minor)) - dev = h; - if (h->radio_dev && (h->radio_dev->minor == minor)) { + list_for_each_entry(dev, &saa7134_devlist, devlist) { + if (dev->video_dev && (dev->video_dev->minor == minor)) + goto found; + if (dev->radio_dev && (dev->radio_dev->minor == minor)) { radio = 1; - dev = h; + goto found; } - if (h->vbi_dev && (h->vbi_dev->minor == minor)) { + if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { type = V4L2_BUF_TYPE_VBI_CAPTURE; - dev = h; + goto found; } } - if (NULL == dev) - return -ENODEV; + return -ENODEV; + found: dprintk("open minor=%d radio=%d type=%s\n",minor,radio, v4l2_type_names[type]); From e77e2c2f2989eefff7e1c0fff9cb72afaedf6796 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: [PATCH 309/310] V4L/DVB (6315): pvrusb2: Change list_for_each+list_entry to list_for_each_entry Signed-off-by: Trent Piepho Reviewed-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 4 +- .../media/video/pvrusb2/pvrusb2-i2c-core.c | 51 ++++++------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index eec83d6ae788..27b12b4b5c88 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3458,7 +3458,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, int setFl,u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG - struct list_head *item; struct pvr2_i2c_client *cp; struct v4l2_register req; int stat = 0; @@ -3471,8 +3470,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, req.reg = reg_id; if (setFl) req.val = *val_ptr; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!v4l2_chip_match_i2c_client( cp->client, req.match_type, req.match_chip)) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 7697f391e8bb..898c9d2e4cdf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -570,15 +570,13 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg) int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg) { - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; int stat = -EINVAL; if (!hdw) return stat; mutex_lock(&hdw->i2c_list_lock); - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (!cp->recv_enable) continue; mutex_unlock(&hdw->i2c_list_lock); stat = pvr2_i2c_client_cmd(cp,cmd,arg); @@ -602,13 +600,11 @@ static int handler_check(struct pvr2_i2c_client *cp) void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw) { - struct list_head *item; struct pvr2_i2c_client *cp; mutex_lock(&hdw->i2c_list_lock); do { struct v4l2_tuner *vtp = &hdw->tuner_signal_info; memset(vtp,0,sizeof(*vtp)); - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) continue; if (!cp->status_poll) continue; cp->status_poll(cp); @@ -630,8 +626,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) { unsigned long msk; unsigned int idx; - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; if (!hdw->i2c_linked) return; if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) { @@ -649,9 +644,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) buf = kmalloc(BUFSIZE,GFP_KERNEL); pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) { cp->ctl_mask = 0; pvr2_i2c_probe(hdw,cp); @@ -687,9 +680,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) "i2c: PEND_STALE (0x%lx)", hdw->i2c_stale_mask); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { m2 = hdw->i2c_stale_mask; m2 &= cp->ctl_mask; m2 &= ~cp->pend_mask; @@ -710,9 +701,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) and update each one. */ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT; - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, + list) { if (!cp->handler) continue; if (!cp->handler->func_table->update) continue; pvr2_trace(PVR2_TRACE_I2C_CORE, @@ -744,10 +734,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { if (!(pm & msk)) continue; pm &= ~msk; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item, - struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, + list) { if (cp->pend_mask & msk) { cp->pend_mask &= ~msk; cp->recv_enable = !0; @@ -771,7 +759,6 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) unsigned long msk,sm,pm; unsigned int idx; const struct pvr2_i2c_op *opf; - struct list_head *item; struct pvr2_i2c_client *cp; unsigned int pt = 0; @@ -790,11 +777,9 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) } if (sm) pt |= PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); - if (!handler_check(cp)) continue; - pt |= PVR2_I2C_PEND_CLIENT; - } + list_for_each_entry(cp, &hdw->i2c_clients, list) + if (handler_check(cp)) + pt |= PVR2_I2C_PEND_CLIENT; if (pt) { mutex_lock(&hdw->i2c_list_lock); do { @@ -882,12 +867,10 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw, char *buf,unsigned int maxlen) { unsigned int ccnt,bcnt; - struct list_head *item; struct pvr2_i2c_client *cp; ccnt = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { bcnt = pvr2_i2c_client_describe( cp, (PVR2_I2C_DETAIL_HANDLER| @@ -925,13 +908,11 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) static int pvr2_i2c_detach_inform(struct i2c_client *client) { struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); - struct pvr2_i2c_client *cp; - struct list_head *item,*nc; + struct pvr2_i2c_client *cp, *ncp; unsigned long amask = 0; int foundfl = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (cp->client == client) { trace_i2c("pvr2_i2c_detach" " [client=%s @ 0x%x ctxt=%p]", From a991f44b79fa49b281eb078eed4a76a42101012a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:43 -0300 Subject: [PATCH 310/310] V4L/DVB (6316): Change list_for_each+list_entry to list_for_each_entry The rest of V4L files. There is one list_for_each+list_entry in cpia_pp.c that wasn't changed because it expects the loop iterator to remain NULL if the list is empty. A bug in vivi is fixed; the 'safe' version needs to be used because the loop deletes the list entries. Simplify a second loop in vivi and get rid if an un-used variable in that loop. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-gpio.c | 6 ++--- drivers/media/video/cx23885/cx23885-core.c | 5 +--- drivers/media/video/dpc7146.c | 5 +--- drivers/media/video/em28xx/em28xx-video.c | 4 +--- drivers/media/video/mxb.c | 4 +--- drivers/media/video/tvmixer.c | 5 +--- drivers/media/video/v4l2-int-device.c | 14 +++-------- drivers/media/video/videobuf-core.c | 5 +--- drivers/media/video/vivi.c | 27 ++++++++-------------- 9 files changed, 20 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index 84154c26f9c5..dce6dae5740e 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) int bttv_sub_del_devices(struct bttv_core *core) { - struct bttv_sub_device *sub; - struct list_head *item,*save; + struct bttv_sub_device *sub, *save; - list_for_each_safe(item,save,&core->subs) { - sub = list_entry(item,struct bttv_sub_device,list); + list_for_each_entry_safe(sub, save, &core->subs, list) { list_del(&sub->list); device_unregister(&sub->dev); } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4d0614093ad6..af16505bd2e0 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1100,7 +1100,6 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - struct list_head *item; dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) @@ -1148,10 +1147,8 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 0fcc935828f8..255dae303708 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -92,7 +92,6 @@ static int dpc_probe(struct saa7146_dev* dev) { struct dpc* dpc = NULL; struct i2c_client *client; - struct list_head *item; dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL); if( NULL == dpc ) { @@ -116,11 +115,9 @@ static int dpc_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&dpc->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &dpc->i2c_adapter.clients, list) if( I2C_SAA7111A == client->addr ) dpc->saa7111a = client; - } /* check if all devices are present */ if( 0 == dpc->saa7111a ) { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index e4fba9068336..b8d5327c438d 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -252,10 +252,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) int minor = iminor(inode); int errCode = 0; struct em28xx *h,*dev = NULL; - struct list_head *list; - list_for_each(list,&em28xx_devlist) { - h = list_entry(list, struct em28xx, devlist); + list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 152cc6b3e152..98ad3092a079 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -153,7 +153,6 @@ static int mxb_probe(struct saa7146_dev* dev) { struct mxb* mxb = NULL; struct i2c_client *client; - struct list_head *item; int result; if ((result = request_module("saa7111")) < 0) { @@ -196,8 +195,7 @@ static int mxb_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&mxb->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &mxb->i2c_adapter.clients, list) { if( I2C_ADDR_TEA6420_1 == client->addr ) mxb->tea6420_1 = client; if( I2C_ADDR_TEA6420_2 == client->addr ) diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 544a4ae7d2ed..9fa5b702e073 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -237,13 +237,10 @@ static const struct file_operations tvmixer_fops = { static int tvmixer_adapters(struct i2c_adapter *adap) { - struct list_head *item; struct i2c_client *client; - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &adap->clients, list) tvmixer_clients(client); - } return 0; } diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index f497c9458344..8b4ef530a3a8 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -34,21 +34,13 @@ static LIST_HEAD(int_list); static void v4l2_int_device_try_attach_all(void) { - struct list_head *head_master; - - list_for_each(head_master, &int_list) { - struct list_head *head_slave; - struct v4l2_int_device *m = - list_entry(head_master, struct v4l2_int_device, head); + struct v4l2_int_device *m, *s; + list_for_each_entry(m, &int_list, head) { if (m->type != v4l2_int_type_master) continue; - list_for_each(head_slave, &int_list) { - struct v4l2_int_device *s = - list_entry(head_slave, - struct v4l2_int_device, head); - + list_for_each_entry(s, &int_list, head) { if (s->type != v4l2_int_type_slave) continue; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 25a98496e3db..c606332512b6 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -517,7 +517,6 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - struct list_head *list; unsigned long flags=0; int retval; @@ -531,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q) q->streaming = 1; if (q->irqlock) spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); + list_for_each_entry(buf, &q->stream, stream) if (buf->state == STATE_PREPARED) q->ops->buf_queue(q,buf); - } if (q->irqlock) spin_unlock_irqrestore(q->irqlock,flags); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 61a6608d6e61..b532aa280a1b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -507,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) static int restart_video_queue(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf, *prev; - struct list_head *item; dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); @@ -521,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) // vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ - list_for_each(item,&dma_q->active) { - buf = list_entry(item, struct vivi_buffer, vb.queue); - + list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); @@ -982,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv, static int vivi_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct vivi_dev *h,*dev = NULL; + struct vivi_dev *dev; struct vivi_fh *fh; - struct list_head *list; - enum v4l2_buf_type type = 0; int i; printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); - list_for_each(list,&vivi_devlist) { - h = list_entry(list, struct vivi_dev, vivi_devlist); - if (h->vfd.minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &vivi_devlist, vivi_devlist) + if (dev->vfd.minor == minor) + goto found; + return -ENODEV; +found: /* If more than one user, mutex should be added */ dev->users++; - dprintk(1,"open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[type],dev->users); + dprintk(1, "open minor=%d type=%s users=%d\n", minor, + v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL);