diff options
Diffstat (limited to 'linux/drivers/media/video')
66 files changed, 3167 insertions, 818 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 54b9f84e9..fe9a4cc14 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -698,6 +698,8 @@ source "drivers/media/video/cx88/Kconfig" source "drivers/media/video/cx23885/Kconfig" +source "drivers/media/video/au0828/Kconfig" + source "drivers/media/video/ivtv/Kconfig" config VIDEO_M32R_AR diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index caf9085c2..f190c0702 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -144,5 +144,7 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_VIDEO_AU0828) += au0828/ + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/linux/drivers/media/video/adv7170.c b/linux/drivers/media/video/adv7170.c index 0d15ce53d..54ef7aa63 100644 --- a/linux/drivers/media/video/adv7170.c +++ b/linux/drivers/media/video/adv7170.c @@ -409,7 +409,7 @@ adv7170_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/adv7175.c b/linux/drivers/media/video/adv7175.c index 86345ba5c..b8618c021 100644 --- a/linux/drivers/media/video/adv7175.c +++ b/linux/drivers/media/video/adv7175.c @@ -427,7 +427,7 @@ adv7175_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig new file mode 100644 index 000000000..f04c80bc8 --- /dev/null +++ b/linux/drivers/media/video/au0828/Kconfig @@ -0,0 +1,13 @@ + +config VIDEO_AU0828 + tristate "Auvitek AU0828 support" + depends on VIDEO_DEV && I2C && INPUT + select I2C_ALGOBIT + select DVB_AU8522 if !DVB_FE_CUSTOMIZE + select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + ---help--- + This is a video4linux driver for Auvitek's USB device. + + To compile this driver as a module, choose M here: the + module will be called au0828 + diff --git a/linux/drivers/media/video/au0828/Makefile b/linux/drivers/media/video/au0828/Makefile new file mode 100644 index 000000000..9f4f572c8 --- /dev/null +++ b/linux/drivers/media/video/au0828/Makefile @@ -0,0 +1,9 @@ +au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o + +obj-$(CONFIG_VIDEO_AU0828) += au0828.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/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c new file mode 100644 index 000000000..8ca91f814 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -0,0 +1,182 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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 "au0828.h" +#include "au0828-cards.h" + +struct au0828_board au0828_boards[] = { + [AU0828_BOARD_UNKNOWN] = { + .name = "Unknown board", + }, + [AU0828_BOARD_HAUPPAUGE_HVR850] = { + .name = "Hauppauge HVR850", + }, + [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { + .name = "Hauppauge HVR950Q", + }, + [AU0828_BOARD_DVICO_FUSIONHDTV7] = { + .name = "DViCO FusionHDTV USB", + }, +}; +const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards); + +/* Tuner callback function for au0828 boards. Currently only needed + * for HVR1500Q, which has an xc5000 tuner. + */ +int au0828_tuner_callback(void *priv, int command, int arg) +{ + struct au0828_dev *dev = priv; + + dprintk(1, "%s()\n", __func__); + + switch (dev->board) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_DVICO_FUSIONHDTV7: + if (command == 0) { + /* Tuner Reset Command from xc5000 */ + /* Drive the tuner into reset and out */ + au0828_clear(dev, REG_001, 2); + mdelay(200); + au0828_set(dev, REG_001, 2); + mdelay(50); + return 0; + } else { + printk(KERN_ERR + "%s(): Unknown command.\n", __func__); + return -EINVAL; + } + break; + } + + return 0; /* Should never be here */ +} + +static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); + + /* Make sure we support the board model */ + switch (tv.model) { + case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */ + case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", __func__, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + __func__, tv.model); +} + +void au0828_card_setup(struct au0828_dev *dev) +{ + static u8 eeprom[256]; + + dprintk(1, "%s()\n", __func__); + + if (dev->i2c_rc == 0) { + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom)); + } + + switch (dev->board) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + if (dev->i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0xa0); + break; + } +} + +/* + * The bridge has between 8 and 12 gpios. + * Regs 1 and 0 deal with output enables. + * Regs 3 and 2 deal with direction. + */ +void au0828_gpio_setup(struct au0828_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + switch (dev->board) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + /* GPIO's + * 4 - CS5340 + * 5 - AU8522 Demodulator + * 6 - eeprom W/P + * 9 - XC5000 Tuner + */ + + /* Into reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0x88 | 0x20); + au0828_write(dev, REG_001, 0x0); + au0828_write(dev, REG_000, 0x0); + msleep(100); + + /* Out of reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_001, 0x02); + au0828_write(dev, REG_002, 0x88 | 0x20); + au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40); + msleep(250); + break; + case AU0828_BOARD_DVICO_FUSIONHDTV7: + /* GPIO's + * 6 - ? + * 8 - AU8522 Demodulator + * 9 - XC5000 Tuner + */ + + /* Into reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0xa0); + au0828_write(dev, REG_001, 0x0); + au0828_write(dev, REG_000, 0x0); + msleep(100); + + /* Out of reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0xa0); + au0828_write(dev, REG_001, 0x02); + au0828_write(dev, REG_000, 0xa0); + msleep(250); + break; + } +} + +/* table of devices that work with this driver */ +struct usb_device_id au0828_usb_id_table [] = { + { USB_DEVICE(0x2040, 0x7200), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7240), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 }, + { USB_DEVICE(0x0fe9, 0xd620), + .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 }, + { }, +}; + +MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); diff --git a/linux/drivers/media/video/au0828/au0828-cards.h b/linux/drivers/media/video/au0828/au0828-cards.h new file mode 100644 index 000000000..118629771 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-cards.h @@ -0,0 +1,26 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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. + */ + +#define AU0828_BOARD_UNKNOWN 0 +#define AU0828_BOARD_HAUPPAUGE_HVR950Q 1 +#define AU0828_BOARD_HAUPPAUGE_HVR850 2 +#define AU0828_BOARD_DVICO_FUSIONHDTV7 3 + diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c new file mode 100644 index 000000000..b3a4346b1 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-core.c @@ -0,0 +1,277 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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 <linux/module.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include "compat.h" +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) +#include <linux/mutex.h> +#endif + +#include "au0828.h" + +/* + * 1 = General debug messages + * 2 = USB handling + * 4 = I2C related + * 8 = Bridge related + */ +unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +unsigned int usb_debug; +module_param(usb_debug, int, 0644); +MODULE_PARM_DESC(usb_debug, "enable usb debug messages"); + +unsigned int bridge_debug; +module_param(bridge_debug, int, 0644); +MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages"); + +#define _AU0828_BULKPIPE 0x03 +#define _BULKPIPESIZE 0xffff + +static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size); +static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size); + +/* USB Direction */ +#define CMD_REQUEST_IN 0x00 +#define CMD_REQUEST_OUT 0x01 + +u32 au0828_readreg(struct au0828_dev *dev, u16 reg) +{ + recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1); + dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]); + return dev->ctrlmsg[0]; +} + +u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val) +{ + dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val); + return send_control_msg(dev, CMD_REQUEST_OUT, val, reg, + dev->ctrlmsg, 0); +} + +static void cmd_msg_dump(struct au0828_dev *dev) +{ + int i; + + for (i = 0; i < sizeof(dev->ctrlmsg); i += 16) + dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + __func__, + dev->ctrlmsg[i+0], dev->ctrlmsg[i+1], + dev->ctrlmsg[i+2], dev->ctrlmsg[i+3], + dev->ctrlmsg[i+4], dev->ctrlmsg[i+5], + dev->ctrlmsg[i+6], dev->ctrlmsg[i+7], + dev->ctrlmsg[i+8], dev->ctrlmsg[i+9], + dev->ctrlmsg[i+10], dev->ctrlmsg[i+11], + dev->ctrlmsg[i+12], dev->ctrlmsg[i+13], + dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]); +} + +static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size) +{ + int status = -ENODEV; + mutex_lock(&dev->mutex); + if (dev->usbdev) { + + /* cp must be memory that has been allocated by kmalloc */ + status = usb_control_msg(dev->usbdev, + usb_sndctrlpipe(dev->usbdev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + cp, size, 1000); + + status = min(status, 0); + + if (status < 0) { + printk(KERN_ERR "%s() Failed sending control message, error %d.\n", + __func__, status); + } + + } + mutex_unlock(&dev->mutex); + return status; +} + +static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size) +{ + int status = -ENODEV; + mutex_lock(&dev->mutex); + if (dev->usbdev) { + + memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg)); + + /* cp must be memory that has been allocated by kmalloc */ + status = usb_control_msg(dev->usbdev, + usb_rcvctrlpipe(dev->usbdev, 0), + request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + cp, size, 1000); + + status = min(status, 0); + + if (status < 0) { + printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", + __func__, status); + } else + cmd_msg_dump(dev); + } + mutex_unlock(&dev->mutex); + return status; +} + +static void au0828_usb_disconnect(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + dprintk(1, "%s()\n", __func__); + + /* Digital TV */ + au0828_dvb_unregister(dev); + + /* I2C */ + au0828_i2c_unregister(dev); + + usb_set_intfdata(interface, NULL); + + mutex_lock(&dev->mutex); + dev->usbdev = NULL; + mutex_unlock(&dev->mutex); + + kfree(dev); + +} + +static int au0828_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int ifnum; + struct au0828_dev *dev; + struct usb_device *usbdev = interface_to_usbdev(interface); + + ifnum = interface->altsetting->desc.bInterfaceNumber; + + if (ifnum != 0) + return -ENODEV; + + dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, + le16_to_cpu(usbdev->descriptor.idVendor), + le16_to_cpu(usbdev->descriptor.idProduct), + ifnum); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); + return -ENOMEM; + } + + mutex_init(&dev->mutex); + mutex_init(&dev->dvb.lock); + dev->usbdev = usbdev; + dev->board = id->driver_info; + + usb_set_intfdata(interface, dev); + + /* Power Up the bridge */ + au0828_write(dev, REG_600, 1 << 4); + + /* Bring up the GPIO's and supporting devices */ + au0828_gpio_setup(dev); + + /* I2C */ + au0828_i2c_register(dev); + + /* Setup */ + au0828_card_setup(dev); + + /* Digital TV */ + au0828_dvb_register(dev); + + printk(KERN_INFO "Registered device AU0828 [%s]\n", + au0828_boards[dev->board].name == NULL ? "Unset" : + au0828_boards[dev->board].name); + + return 0; +} + +static struct usb_driver au0828_usb_driver = { + .name = DRIVER_NAME, + .probe = au0828_usb_probe, + .disconnect = au0828_usb_disconnect, + .id_table = au0828_usb_id_table, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15) + .owner = THIS_MODULE, +#endif +}; + +static int __init au0828_init(void) +{ + int ret; + + if (debug) + printk(KERN_INFO "%s() Debugging is enabled\n", __func__); + + if (usb_debug) { + printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); + debug |= 2; + } + + if (i2c_debug) { + printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); + debug |= 4; + } + + if (bridge_debug) { + printk(KERN_INFO "%s() Bridge Debugging is enabled\n", + __func__); + debug |= 8; + } + + printk(KERN_INFO "au0828 driver loaded\n"); + + ret = usb_register(&au0828_usb_driver); + if (ret) + printk(KERN_ERR "usb_register failed, error = %d\n", ret); + + return ret; +} + +static void __exit au0828_exit(void) +{ + usb_deregister(&au0828_usb_driver); +} + +module_init(au0828_init); +module_exit(au0828_exit); + +MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); +MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_LICENSE("GPL"); + diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c new file mode 100644 index 000000000..f911bbac6 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-dvb.c @@ -0,0 +1,402 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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 <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <media/v4l2-common.h> +#include "compat.h" + +#include "au0828.h" +#include "au8522.h" +#include "xc5000.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define _AU0828_BULKPIPE 0x83 +#define _BULKPIPESIZE 0xe522 + +static struct au8522_config hauppauge_hvr950q_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, +}; + +static struct xc5000_config hauppauge_hvr950q_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 6000, + .tuner_callback = au0828_tuner_callback +}; + +/*-------------------------------------------------------------------*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void urb_completion(struct urb *purb, struct pt_regs *regs) +#else +static void urb_completion(struct urb *purb) +#endif +{ + u8 *ptr; + struct au0828_dev *dev = purb->context; + int ptype = usb_pipetype(purb->pipe); + + dprintk(2, "%s()\n", __func__); + + if (!dev) + return; + + if (dev->urb_streaming == 0) + return; + + if (ptype != PIPE_BULK) { + printk(KERN_ERR "%s() Unsupported URB type %d\n", + __func__, ptype); + return; + } + + ptr = (u8 *)purb->transfer_buffer; + + /* Feed the transport payload into the kernel demux */ + dvb_dmx_swfilter_packets(&dev->dvb.demux, + purb->transfer_buffer, purb->actual_length / 188); + + /* Clean the buffer before we requeue */ + memset(purb->transfer_buffer, 0, URB_BUFSIZE); + + /* Requeue URB */ + usb_submit_urb(purb, GFP_ATOMIC); +} + +static int stop_urb_transfer(struct au0828_dev *dev) +{ + int i; + + dprintk(2, "%s()\n", __func__); + + for (i = 0; i < URB_COUNT; i++) { + usb_kill_urb(dev->urbs[i]); + kfree(dev->urbs[i]->transfer_buffer); + usb_free_urb(dev->urbs[i]); + } + + dev->urb_streaming = 0; + + return 0; +} + +static int start_urb_transfer(struct au0828_dev *dev) +{ + struct urb *purb; + int i, ret = -ENOMEM; + + dprintk(2, "%s()\n", __func__); + + if (dev->urb_streaming) { + dprintk(2, "%s: iso xfer already running!\n", __func__); + return 0; + } + + for (i = 0; i < URB_COUNT; i++) { + + dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->urbs[i]) + goto err; + + purb = dev->urbs[i]; + + purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); + if (!purb->transfer_buffer) { + usb_free_urb(purb); + dev->urbs[i] = 0; + goto err; + } + + purb->status = -EINPROGRESS; + usb_fill_bulk_urb(purb, + dev->usbdev, + usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE), + purb->transfer_buffer, + URB_BUFSIZE, + urb_completion, + dev); + + } + + for (i = 0; i < URB_COUNT; i++) { + ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); + if (ret != 0) { + stop_urb_transfer(dev); + printk(KERN_ERR "%s: failed urb submission, " + "err = %d\n", __func__, ret); + return ret; + } + } + + dev->urb_streaming = 1; + ret = 0; + +err: + return ret; +} + +static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dvb *dvb = &dev->dvb; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + if (!demux->dmx.frontend) + return -EINVAL; + + if (dvb) { + mutex_lock(&dvb->lock); + if (dvb->feeding++ == 0) { + /* Start transport */ + au0828_write(dev, 0x608, 0x90); + au0828_write(dev, 0x609, 0x72); + au0828_write(dev, 0x60a, 0x71); + au0828_write(dev, 0x60b, 0x01); + ret = start_urb_transfer(dev); + } + mutex_unlock(&dvb->lock); + } + + return ret; +} + +static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dvb *dvb = &dev->dvb; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + if (dvb) { + mutex_lock(&dvb->lock); + if (--dvb->feeding == 0) { + /* Stop transport */ + au0828_write(dev, 0x608, 0x00); + au0828_write(dev, 0x609, 0x00); + au0828_write(dev, 0x60a, 0x00); + au0828_write(dev, 0x60b, 0x00); + ret = stop_urb_transfer(dev); + } + mutex_unlock(&dvb->lock); + } + + return ret; +} + +int dvb_register(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + int result; + + dprintk(1, "%s()\n", __func__); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, + &dev->usbdev->dev, adapter_nr); + if (result < 0) { + printk(KERN_ERR "%s: dvb_register_adapter failed " + "(errno = %d)\n", DRIVER_NAME, result); + goto fail_adapter; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb->adapter.priv = dev; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); +#else + dvb->adapter->priv = dev; + + /* register frontend */ + result = dvb_register_frontend(dvb->adapter, dvb->frontend); +#endif + if (result < 0) { + printk(KERN_ERR "%s: dvb_register_frontend failed " + "(errno = %d)\n", DRIVER_NAME, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dev; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = au0828_dvb_start_feed; + dvb->demux.stop_feed = au0828_dvb_stop_feed; + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); +#else + result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter); +#endif + if (result < 0) { + printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_fe_conn; + } + + /* register network adapter */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); +#else + dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx); +#endif + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_unregister_adapter(&dvb->adapter); +#else + dvb_unregister_adapter(dvb->adapter); +#endif +fail_adapter: + return result; +} + +void au0828_dvb_unregister(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + dprintk(1, "%s()\n", __func__); + + if (dvb->frontend == NULL) + return; + + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_unregister_adapter(&dvb->adapter); +#else + dvb_unregister_adapter(dvb->adapter); +#endif +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. No other function in this file needs + * to change. + */ +int au0828_dvb_register(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + int ret; + + dprintk(1, "%s()\n", __func__); + + /* init frontend */ + switch (dev->board) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_DVICO_FUSIONHDTV7: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_hvr950q_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) { + hauppauge_hvr950q_tunerconfig.priv = dev; + dvb_attach(xc5000_attach, dvb->frontend, + &dev->i2c_adap, + &hauppauge_hvr950q_tunerconfig); + } + break; + default: + printk(KERN_WARNING "The frontend of your DVB/ATSC card " + "isn't supported yet\n"); + break; + } + if (NULL == dvb->frontend) { + printk(KERN_ERR "%s() Frontend initialization failed\n", + __func__); + return -1; + } + + /* Put the analog decoder in standby to keep it quiet */ + au0828_call_i2c_clients(dev, TUNER_SET_STANDBY, NULL); + + if (dvb->frontend->ops.analog_ops.standby) + dvb->frontend->ops.analog_ops.standby(dvb->frontend); + + /* register everything */ + ret = dvb_register(dev); + if (ret < 0) { + if (dvb->frontend->ops.release) + dvb->frontend->ops.release(dvb->frontend); + return ret; + } + + return 0; +} + diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c new file mode 100644 index 000000000..08d2a6080 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-i2c.c @@ -0,0 +1,388 @@ +/* + * Driver for the Auvitek AU0828 USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include "compat.h" +#include "au0828.h" + +#include <media/v4l2-common.h> + +unsigned int i2c_debug; +module_param(i2c_debug, int, 0444); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +#define I2C_WAIT_DELAY 512 +#define I2C_WAIT_RETRY 64 + +static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, REG_201) & 0x08 ? 0 : 1; +} + +static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, REG_201) & 0x02 ? 0 : 1; +} + +static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_slave_did_read_ack(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, REG_201) & 0x01 ? 0 : 1; +} + +static int i2c_wait_read_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_read_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, REG_201) & 0x04 ? 1 : 0; +} + +static int i2c_wait_write_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (i2c_is_write_done(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, REG_201) & 0x10 ? 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; +} + +/* FIXME: Implement join handling correctly */ +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined_rlen) +{ + int i, strobe = 0; + struct au0828_dev *dev = i2c_adap->algo_data; + + dprintk(4, "%s()\n", __func__); + + au0828_write(dev, REG_2FF, 0x01); + au0828_write(dev, REG_202, 0x07); + + /* Hardware needs 8 bit addresses */ + au0828_write(dev, REG_203, msg->addr << 1); + + dprintk(4, "SEND: %02x\n", msg->addr); + + for (i = 0; i < msg->len;) { + + dprintk(4, " %02x\n", msg->buf[i]); + + au0828_write(dev, REG_205, msg->buf[i]); + + strobe++; + i++; + + if ((strobe >= 4) || (i >= msg->len)) { + + /* Strobe the byte into the bus */ + if (i < msg->len) + au0828_write(dev, REG_200, 0x41); + else + au0828_write(dev, REG_200, 0x01); + + /* Reset strobe trigger */ + strobe = 0; + + if (!i2c_wait_write_done(i2c_adap)) + return -EIO; + + } + + } + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + dprintk(4, "\n"); + + return msg->len; +} + +/* FIXME: Implement join handling correctly */ +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + int i; + + dprintk(4, "%s()\n", __func__); + + au0828_write(dev, REG_2FF, 0x01); + au0828_write(dev, REG_202, 0x07); + + /* Hardware needs 8 bit addresses */ + au0828_write(dev, REG_203, msg->addr << 1); + + dprintk(4, " RECV:\n"); + + /* Deal with i2c_scan */ + if (msg->len == 0) { + au0828_write(dev, REG_200, 0x20); + if (i2c_wait_read_ack(i2c_adap)) + return -EIO; + return 0; + } + + for (i = 0; i < msg->len;) { + + i++; + + if (i < msg->len) + au0828_write(dev, REG_200, 0x60); + else + au0828_write(dev, REG_200, 0x20); + + if (!i2c_wait_read_done(i2c_adap)) + return -EIO; + + msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff; + + dprintk(4, " %02x\n", msg->buf[i-1]); + } + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + dprintk(4, "\n"); + + return msg->len; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + int i, retval = 0; + + dprintk(4, "%s(num = %d)\n", __func__, num); + + for (i = 0; i < num; i++) { + dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __func__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); + if (retval < 0) + goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); + } + if (retval < 0) + goto err; + } + return num; + +err: + return retval; +} + +static int attach_inform(struct i2c_client *client) +{ + 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) +{ + dprintk(1, "i2c detach [client=%s]\n", client->name); + + return 0; +} + +void au0828_call_i2c_clients(struct au0828_dev *dev, + unsigned int cmd, void *arg) +{ + if (dev->i2c_rc != 0) + return; + + i2c_clients_command(&dev->i2c_adap, cmd, arg); +} + +static u32 au0828_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +static struct i2c_algorithm au0828_i2c_algo_template = { + .master_xfer = i2c_xfer, + .functionality = au0828_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter au0828_i2c_adap_template = { + .name = DRIVER_NAME, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + .owner = THIS_MODULE, +#endif + .id = I2C_HW_B_AU0828, + .algo = &au0828_i2c_algo_template, + .class = I2C_CLASS_TV_ANALOG, + .client_register = attach_inform, + .client_unregister = detach_inform, +}; + +static struct i2c_client au0828_i2c_client_template = { + .name = "au0828 internal", +}; + +static char *i2c_devs[128] = { + [0x8e >> 1] = "au8522", + [0xa0 >> 1] = "eeprom", + [0xc2 >> 1] = "tuner/xc5000", +}; + +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(KERN_INFO "%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 au0828_i2c_register(struct au0828_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + memcpy(&dev->i2c_adap, &au0828_i2c_adap_template, + sizeof(dev->i2c_adap)); + memcpy(&dev->i2c_algo, &au0828_i2c_algo_template, + sizeof(dev->i2c_algo)); + memcpy(&dev->i2c_client, &au0828_i2c_client_template, + sizeof(dev->i2c_client)); + + dev->i2c_adap.dev.parent = &dev->usbdev->dev; + + strlcpy(dev->i2c_adap.name, DRIVER_NAME, + sizeof(dev->i2c_adap.name)); + + dev->i2c_algo.data = dev; + dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, dev); + i2c_add_adapter(&dev->i2c_adap); + + dev->i2c_client.adapter = &dev->i2c_adap; + + if (0 == dev->i2c_rc) { + printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME); + if (i2c_scan) + do_i2c_scan(DRIVER_NAME, &dev->i2c_client); + } else + printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME); + + return dev->i2c_rc; +} + +int au0828_i2c_unregister(struct au0828_dev *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} + diff --git a/linux/drivers/media/video/au0828/au0828-reg.h b/linux/drivers/media/video/au0828/au0828-reg.h new file mode 100644 index 000000000..398275508 --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828-reg.h @@ -0,0 +1,38 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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. + */ + +/* We'll start to rename these registers once we have a better + * understanding of their meaning. + */ +#define REG_000 0x000 +#define REG_001 0x001 +#define REG_002 0x002 +#define REG_003 0x003 + +#define REG_200 0x200 +#define REG_201 0x201 +#define REG_202 0x202 +#define REG_203 0x203 +#define REG_205 0x205 +#define REG_209 0x209 +#define REG_2FF 0x2ff + +#define REG_600 0x600 diff --git a/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h new file mode 100644 index 000000000..4b0ad1b3e --- /dev/null +++ b/linux/drivers/media/video/au0828/au0828.h @@ -0,0 +1,137 @@ +/* + * Driver for the Auvitek AU0828 USB bridge + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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 <linux/usb.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <media/tveeprom.h> + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +#include "au0828-reg.h" +#include "au0828-cards.h" + +#define DRIVER_NAME "au0828" +#define URB_COUNT 16 +#define URB_BUFSIZE (0xe522) + +struct au0828_board { + char *name; +}; + +struct au0828_dvb { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) + struct mutex lock; +#else + struct semaphore lock; +#endif + struct dvb_adapter adapter; + struct dvb_frontend *frontend; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; + int feeding; +}; + +struct au0828_dev { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) + struct mutex mutex; +#else + struct semaphore mutex; +#endif + struct usb_device *usbdev; + int board; + u8 ctrlmsg[64]; + + /* I2C */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* Digital */ + struct au0828_dvb dvb; + + /* USB / URB Related */ + int urb_streaming; + struct urb *urbs[URB_COUNT]; + +}; + +struct au0828_buff { + struct au0828_dev *dev; + struct urb *purb; + struct list_head buff_list; +}; + +/* ----------------------------------------------------------- */ +#define au0828_read(dev, reg) au0828_readreg(dev, reg) +#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value) +#define au0828_andor(dev, reg, mask, value) \ + au0828_writereg(dev, reg, \ + (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask))) + +#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit)) +#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0) + +/* ----------------------------------------------------------- */ +/* au0828-core.c */ +extern u32 au0828_read(struct au0828_dev *dev, u16 reg); +extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val); +extern unsigned int debug; +extern unsigned int usb_debug; +extern unsigned int bridge_debug; + +/* ----------------------------------------------------------- */ +/* au0828-cards.c */ +extern struct au0828_board au0828_boards[]; +extern struct usb_device_id au0828_usb_id_table[]; +extern const unsigned int au0828_bcount; +extern void au0828_gpio_setup(struct au0828_dev *dev); +extern int au0828_tuner_callback(void *priv, int command, int arg); +extern void au0828_card_setup(struct au0828_dev *dev); + +/* ----------------------------------------------------------- */ +/* au0828-i2c.c */ +extern int au0828_i2c_register(struct au0828_dev *dev); +extern int au0828_i2c_unregister(struct au0828_dev *dev); +extern void au0828_call_i2c_clients(struct au0828_dev *dev, + unsigned int cmd, void *arg); +extern unsigned int i2c_debug; + +/* ----------------------------------------------------------- */ +/* au0828-dvb.c */ +extern int au0828_dvb_register(struct au0828_dev *dev); +extern void au0828_dvb_unregister(struct au0828_dev *dev); + +#define dprintk(level, fmt, arg...)\ + do { if (debug & level)\ + printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ + } while (0) + diff --git a/linux/drivers/media/video/bt819.c b/linux/drivers/media/video/bt819.c index 9264e2cff..402bccaf7 100644 --- a/linux/drivers/media/video/bt819.c +++ b/linux/drivers/media/video/bt819.c @@ -525,7 +525,7 @@ bt819_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/bt856.c b/linux/drivers/media/video/bt856.c index 7abfad9a4..50ca987ad 100644 --- a/linux/drivers/media/video/bt856.c +++ b/linux/drivers/media/video/bt856.c @@ -312,7 +312,7 @@ bt856_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index c1173a94a..303422115 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -3506,6 +3506,9 @@ static int radio_release(struct inode *inode, struct file *file) struct bttv *btv = fh->btv; struct rds_command cmd; + file->private_data = NULL; + kfree(fh); + btv->radio_user--; bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd); diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c index 479ef617b..a5f5b8a4a 100644 --- a/linux/drivers/media/video/c-qcam.c +++ b/linux/drivers/media/video/c-qcam.c @@ -39,6 +39,7 @@ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) #include <linux/mutex.h> #endif +#include <linux/jiffies.h> #include <asm/uaccess.h> @@ -102,7 +103,8 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam, unsigned long oldjiffies = jiffies; unsigned int i; - for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); ) + for (oldjiffies = jiffies; + time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); ) if (qcam_ready1(qcam) == value) return 0; @@ -127,7 +129,8 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) unsigned long oldjiffies = jiffies; unsigned int i; - for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); ) + for (oldjiffies = jiffies; + time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); ) if (qcam_ready2(qcam) == value) return 0; diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig index 1fd326fe4..ca5fbce3a 100644 --- a/linux/drivers/media/video/cx23885/Kconfig +++ b/linux/drivers/media/video/cx23885/Kconfig @@ -8,6 +8,7 @@ config VIDEO_CX23885 select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB + select VIDEO_CX25840 select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE @@ -16,6 +17,7 @@ config VIDEO_CX23885 select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE select DVB_TDA18271 if !DVB_FE_CUSTOMIZE select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select DVB_TDA10048 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index 6f04004b7..0c25b7dd1 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -131,6 +131,14 @@ struct cx23885_board cx23885_boards[] = { .name = "Hauppauge WinTV-HVR1500", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1200] = { + .name = "Hauppauge WinTV-HVR1200", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1700] = { + .name = "Hauppauge WinTV-HVR1700", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -182,6 +190,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7717, .card = CX23885_BOARD_HAUPPAUGE_HVR1500, + }, { + .subvendor = 0x0070, + .subdevice = 0x71d1, + .card = CX23885_BOARD_HAUPPAUGE_HVR1200, + }, { + .subvendor = 0x0070, + .subdevice = 0x8101, + .card = CX23885_BOARD_HAUPPAUGE_HVR1700, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -236,6 +252,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */ case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */ case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */ + case 81519: + /* WinTV-HVR1700 (PCIe, Retail, No IR, half height, + * DVB-T and MPEG2 HW Encoder */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); @@ -315,6 +334,38 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x00040004); mdelay(20); break; + case CX23885_BOARD_HAUPPAUGE_HVR1200: + /* GPIO-0 tda10048 demodulator reset */ + /* GPIO-2 tda18271 tuner reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00050000); + mdelay(20); + cx_clear(GP0_IO, 0x00000005); + mdelay(20); + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1700: + /* GPIO-0 TDA10048 demodulator reset */ + /* GPIO-2 TDA8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + + /* The following GPIO's are on the interna AVCore (cx25840) */ + /* GPIO-19 IR_RX */ + /* GPIO-20 IR_TX 416/DVBT Select */ + /* GPIO-21 IIS DAT */ + /* GPIO-22 IIS WCLK */ + /* GPIO-23 IIS BCLK */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00050000); + mdelay(20); + cx_clear(GP0_IO, 0x00000005); + mdelay(20); + cx_set(GP0_IO, 0x00050005); + break; } } @@ -325,6 +376,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1200: /* FIXME: Implement me */ break; } @@ -354,6 +406,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -370,12 +424,24 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: 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; } + /* Certain boards support analog, or require the avcore to be + * loaded, ensure this happens. + */ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + request_module("cx25840"); + break; + } } /* ------------------------------------------------------------------ */ diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index 309c17586..968b31716 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -745,8 +745,8 @@ static int cx23885_dev_setup(struct cx23885_dev *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_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); cx23885_ir_init(dev); if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 689c54541..5923f214e 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -37,9 +37,9 @@ #include "tda18271.h" #include "lgdt330x.h" #include "xc5000.h" +#include "tda10048.h" #include "dvb-pll.h" #include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" #include "tuner-simple.h" static unsigned int debug; @@ -108,6 +108,13 @@ static struct s5h1409_config hauppauge_generic_config = { .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct tda10048_config hauppauge_hvr1200_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON +}; + static struct s5h1409_config hauppauge_ezqam_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, @@ -179,6 +186,10 @@ static struct tda18271_config hauppauge_tda18271_config = { .gate = TDA18271_GATE_ANALOG, }; +static struct tda18271_config hauppauge_hvr1200_tuner_config = { + .gate = TDA18271_GATE_ANALOG, +}; + static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) { struct cx23885_tsport *port = ptr; @@ -309,7 +320,7 @@ static int dvb_register(struct cx23885_tsport *port) static struct xc2028_ctrl ctl = { .fname = "xc3028-v27.fw", .max_len = 64, - .scode_table = OREN538, + .scode_table = XC3028_FE_OREN538, }; fe = dvb_attach(xc2028_attach, @@ -318,6 +329,21 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + i2c_bus = &dev->i2c_bus[0]; + port->dvb.frontend = dvb_attach(tda10048_attach, + &hauppauge_hvr1200_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, port->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, 0x42, + &tda829x_no_probe); + dvb_attach(tda18271_attach, port->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr1200_tuner_config); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c index a06d50396..972c58cc9 100644 --- a/linux/drivers/media/video/cx23885/cx23885-i2c.c +++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c @@ -374,6 +374,7 @@ static struct i2c_client cx23885_i2c_client_template = { }; static char *i2c_devs[128] = { + [0x10 >> 1] = "tda10048", [ 0x1c >> 1 ] = "lgdt3303", [ 0x86 >> 1 ] = "tda9887", [ 0x32 >> 1 ] = "cx24227", diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index d66fe2484..7eaadeab6 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -62,6 +62,8 @@ #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 #define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 #define CX23885_BOARD_HAUPPAUGE_HVR1500 6 +#define CX23885_BOARD_HAUPPAUGE_HVR1200 7 +#define CX23885_BOARD_HAUPPAUGE_HVR1700 8 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index 82e7fb267..7e21143e2 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -1297,6 +1297,12 @@ static int cx25840_probe(struct i2c_client *client) state->id = id; state->rev = device_id; + if (state->is_cx23885) { + /* Drive GPIO2 direction and values */ + cx25840_write(client, 0x160, 0x1d); + cx25840_write(client, 0x164, 0x00); + } + return 0; } diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index fcecfeed9..0809039a5 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1410,6 +1410,10 @@ static const struct cx88_board cx88_boards[] = { }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xe780, + }, }, [CX88_BOARD_ADSTECH_PTV_390] = { .name = "ADS Tech Instant Video PCI", diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 8559ef873..7d35590f9 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -46,7 +46,6 @@ #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" -#include "tuner-xc2028-types.h" #include "tuner-simple.h" #include "tda9887.h" @@ -820,7 +819,7 @@ static int dvb_register(struct cx8802_dev *dev) static struct xc2028_ctrl ctl = { .fname = "xc3028-v27.fw", .max_len = 64, - .scode_table = OREN538, + .scode_table = XC3028_FE_OREN538, }; fe = dvb_attach(xc2028_attach, diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c index 258d46407..4bfb3076b 100644 --- a/linux/drivers/media/video/dpc7146.c +++ b/linux/drivers/media/video/dpc7146.c @@ -132,7 +132,7 @@ static int dpc_probe(struct saa7146_dev* dev) device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients); /* check if all devices are present */ - if( 0 == dpc->saa7111a ) { + if (!dpc->saa7111a) { DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); i2c_del_adapter(&dpc->i2c_adapter); kfree(dpc); diff --git a/linux/drivers/media/video/em28xx/Kconfig b/linux/drivers/media/video/em28xx/Kconfig index 0f7a0bd86..3d9082fa6 100644 --- a/linux/drivers/media/video/em28xx/Kconfig +++ b/linux/drivers/media/video/em28xx/Kconfig @@ -1,11 +1,13 @@ config VIDEO_EM28XX - tristate "Empia EM2800/2820/2840 USB video capture support" + tristate "Empia EM28xx USB video capture support" depends on VIDEO_DEV && I2C && INPUT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEOBUF_VMALLOC select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO ---help--- This is a video4linux driver for Empia 28xx based TV cards. @@ -27,3 +29,14 @@ config VIDEO_EM28XX_ALSA To compile this driver as a module, choose M here: the module will be called em28xx-alsa +config VIDEO_EM28XX_DVB + tristate "DVB/ATSC Support for em28xx based TV cards" + depends on VIDEO_EM28XX && DVB_CORE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select VIDEOBUF_DVB + select FW_LOADER + ---help--- + This adds support for DVB cards based on the + Empiatech em28xx chips. + diff --git a/linux/drivers/media/video/em28xx/Makefile b/linux/drivers/media/video/em28xx/Makefile index 092455099..3d1c3cc33 100644 --- a/linux/drivers/media/video/em28xx/Makefile +++ b/linux/drivers/media/video/em28xx/Makefile @@ -5,6 +5,7 @@ em28xx-alsa-objs := em28xx-audio.o obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o +obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o EXTRA_CFLAGS += -Idrivers/media/video EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 06a4e4a2b..bdf64cd9c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -37,7 +37,6 @@ #include <media/v4l2-common.h> #include "em28xx.h" -#include "tuner-xc2028.h" static int tuner = -1; module_param(tuner, int, 0444); @@ -53,26 +52,6 @@ struct em28xx_hash_table { unsigned int tuner; }; -/* Boards supported by driver */ - -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 - struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", @@ -201,6 +180,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, + .has_dvb = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -215,9 +195,6 @@ struct em28xx_board em28xx_boards[] = { .vmux = TVP5150_SVIDEO, .amux = 1, } }, - - /* gpio's 4, 1, 0 */ - .analog_gpio = 0x003d2d, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", @@ -454,7 +431,36 @@ struct usb_device_id em28xx_id_table [] = { }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); -/* EEPROM hash table for devices with generic USB IDs */ +/* + * Reset sequences for analog/digital modes + */ + +/* Board Hauppauge WinTV HVR 900 analog */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { + {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, + {0x05, 0xff, 0x10, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 digital */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { + {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x04, 0x0f, 10}, + {EM2880_R04_GPO, 0x0c, 0x0f, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 tuner_callback */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = { + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* + * EEPROM hash table for devices with generic USB IDs + */ static struct em28xx_hash_table em28xx_eeprom_hash [] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, @@ -466,79 +472,113 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, }; +int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + if (command != XC2028_TUNER_RESET) + return 0; + + if (dev->mode == EM28XX_ANALOG_MODE) + rc = em28xx_gpio_set(dev, dev->tun_analog_gpio); + else + rc = em28xx_gpio_set(dev, dev->tun_digital_gpio); + + return rc; +} +EXPORT_SYMBOL_GPL(em28xx_tuner_callback); + +static void em28xx_set_model(struct em28xx *dev) +{ + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; + dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; + dev->has_dvb = em28xx_boards[dev->model].has_dvb; +} + /* Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ void em28xx_pre_card_setup(struct em28xx *dev) { + int rc; + + rc = em28xx_read_reg(dev, EM2880_R04_GPO); + if (rc >= 0) + dev->reg_gpo = rc; + + dev->wait_after_write = 5; + rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); + if (rc > 0) { + switch (rc) { + case CHIP_ID_EM2883: + em28xx_info("chip ID is em2882/em2883\n"); + dev->wait_after_write = 0; + break; + default: + em28xx_info("em28xx chip ID = %d\n", rc); + } + } + em28xx_set_model(dev); + /* request some modules */ switch (dev->model) { case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_TERRATEC_HYBRID_XS: - em28xx_write_regs(dev, XCLK_REG, "\x27", 1); - em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1); - em28xx_write_regs(dev, 0x08, "\xff", 1); - em28xx_write_regs(dev, 0x04, "\x00", 1); - msleep(100); - em28xx_write_regs(dev, 0x04, "\x08", 1); - msleep(100); - em28xx_write_regs(dev, 0x08, "\xff", 1); - msleep(50); - em28xx_write_regs(dev, 0x08, "\x2d", 1); + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); msleep(50); - em28xx_write_regs(dev, 0x08, "\x3d", 1); + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = hauppauge_wintv_hvr_900_analog; + dev->digital_gpio = hauppauge_wintv_hvr_900_digital; + dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback; + dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback; + break; } + + em28xx_gpio_set(dev, dev->tun_analog_gpio); + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + + /* Unlock device */ + em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); } -static int em28xx_tuner_callback(void *ptr, int command, int arg) +static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) { - int rc = 0; - struct em28xx *dev = ptr; + memset(ctl, 0, sizeof(*ctl)); - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_TUNER_RESET: - { - /* GPIO and initialization codes for analog TV and radio - This code should be complemented for DTV, since reset - codes are different. - */ - - dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); - dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - - if (dev->analog_gpio) { - char gpio0 = dev->analog_gpio & 0xff; - char gpio1 = (dev->analog_gpio >> 8) & 0xff; - char gpio4 = dev->analog_gpio >> 24; - - if (gpio4) { - dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); - msleep(140); - } - - msleep(6); - dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); - msleep(10); - dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); - msleep(5); - } + ctl->fname = XC2028_DEFAULT_FIRMWARE; + ctl->max_len = 64; + ctl->mts = em28xx_boards[dev->model].mts_firmware; + switch (dev->model) { + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + ctl->demod = XC3028_FE_ZARLINK456; break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + /* FIXME: Better to specify the needed IF */ + ctl->demod = XC3028_FE_DEFAULT; + break; + default: + ctl->demod = XC3028_FE_OREN538; } - } - return rc; } static void em28xx_config_tuner(struct em28xx *dev) { struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; struct tuner_setup tun_setup; struct v4l2_frequency f; @@ -553,11 +593,9 @@ static void em28xx_config_tuner(struct em28xx *dev) em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); if (dev->tuner_type == TUNER_XC2028) { - memset(&ctl, 0, sizeof(ctl)); + struct xc2028_ctrl ctl; - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - ctl.mts = em28xx_boards[dev->model].mts_firmware; + em28xx_setup_xc3028(dev, &ctl); xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; @@ -655,19 +693,6 @@ static int em28xx_hint_board(struct em28xx *dev) return -1; } - -static void em28xx_set_model(struct em28xx *dev) -{ - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; - dev->decoder = em28xx_boards[dev->model].decoder; - dev->video_inputs = em28xx_boards[dev->model].vchannels; - dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; - dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; - dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; -} - /* ----------------------------------------------------------------------- */ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) { diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 97635abb9..393425487 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -53,6 +53,12 @@ static int alt = EM28XX_PINOUT; module_param(alt, int, 0644); MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); +/* FIXME */ +#define em28xx_isocdbg(fmt, arg...) do {\ + if (core_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + /* * em28xx_read_reg_req() * reads data from the usb device specifying bRequest @@ -71,11 +77,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, buf, len, HZ); - if (reg_debug){ + if (reg_debug) { printk(ret < 0 ? " failed!\n" : "%02x values: ", ret); - for (byte = 0; byte < len; byte++) { + for (byte = 0; byte < len; byte++) printk(" %02x", (unsigned char)buf[byte]); - } + printk("\n"); } @@ -128,7 +134,10 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, unsigned char *bufs; if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); + return -ENODEV; + + if (len < 1) + return -EINVAL; bufs = kmalloc(len, GFP_KERNEL); @@ -137,8 +146,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if (reg_debug) { int i; for (i = 0; i < len; ++i) - printk (" %02x", (unsigned char)buf[i]); - printk ("\n"); + printk(" %02x", (unsigned char)buf[i]); + printk("\n"); } if (!bufs) @@ -147,14 +156,32 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, bufs, len, HZ); - msleep(5); /* FIXME: magic number */ + if (dev->wait_after_write) + msleep(dev->wait_after_write); + kfree(bufs); return ret; } int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) { - return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len); + int rc; + + rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len); + + /* Stores GPO/GPIO values at the cache, if changed + Only write values should be stored, since input on a GPIO + register will return the input bits. + Not sure what happens on reading GPO register. + */ + if (rc >= 0) { + if (reg == EM2880_R04_GPO) + dev->reg_gpo = buf[0]; + else if (reg == EM28XX_R08_GPIO) + dev->reg_gpio = buf[0]; + } + + return rc; } /* @@ -167,9 +194,20 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, { int oldval; u8 newval; - if ((oldval = em28xx_read_reg(dev, reg)) < 0) + + /* Uses cache for gpo/gpio registers */ + if (reg == EM2880_R04_GPO) + oldval = dev->reg_gpo; + else if (reg == EM28XX_R08_GPIO) + oldval = dev->reg_gpio; + else + oldval = em28xx_read_reg(dev, reg); + + if (oldval < 0) return oldval; + newval = (((u8) oldval) & ~bitmask) | (val & bitmask); + return em28xx_write_regs(dev, reg, &newval, 1); } @@ -181,20 +219,26 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) { int ret, i; u8 addr = reg & 0x7f; - if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0) + + ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2); + if (ret < 0) return ret; - if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0) + + ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); + if (ret < 0) return ret; /* Wait up to 50 ms for AC97 command to complete */ for (i = 0; i < 10; i++) { - if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0) + ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); + if (ret < 0) return ret; + if (!(ret & 0x01)) return 0; msleep(5); } - em28xx_warn ("AC97 command still being executed: not handled properly!\n"); + em28xx_warn("AC97 command still being executed: not handled properly!\n"); return 0; } @@ -212,7 +256,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) else input = EM2800_AUDIO_SRC_TUNER; - ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1); + ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); if (ret < 0) return ret; } @@ -238,7 +282,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) } } - ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); + ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); if (ret < 0) return ret; msleep(5); @@ -246,11 +290,11 @@ static int em28xx_set_audio_source(struct em28xx *dev) /* Sets AC97 mixer registers This is seems to be needed, even for non-ac97 configs */ - ret = em28xx_write_ac97(dev, VIDEO_AC97, video); + ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video); if (ret < 0) return ret; - ret = em28xx_write_ac97(dev, LINE_IN_AC97, line); + ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line); return ret; } @@ -266,7 +310,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Mute */ s[1] |= 0x80; - ret = em28xx_write_ac97(dev, MASTER_AC97, s); + ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); if (ret < 0) return ret; @@ -277,7 +321,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (!dev->mute) xclk |= 0x80; - ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7); + ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7); if (ret < 0) return ret; msleep(10); @@ -288,7 +332,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Unmute device */ if (!dev->mute) s[1] &= ~0x80; - ret = em28xx_write_ac97(dev, MASTER_AC97, s); + ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); return ret; } @@ -296,50 +340,68 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); int em28xx_colorlevels_set_default(struct em28xx *dev) { - em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */ - em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */ - em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */ - em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1); - em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1); - em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1); - - em28xx_write_regs(dev, GAMMA_REG, "\x20", 1); - em28xx_write_regs(dev, RGAIN_REG, "\x20", 1); - em28xx_write_regs(dev, GGAIN_REG, "\x20", 1); - em28xx_write_regs(dev, BGAIN_REG, "\x20", 1); - em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1); - em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1); - return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1); + em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ + em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */ + em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */ + em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1); + em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1); + em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1); + + em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1); + em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1); + em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1); + em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1); + em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1); + em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1); + return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1); } int em28xx_capture_start(struct em28xx *dev, int start) { - int ret; + int rc; /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ - if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00, - 0x10)) < 0) - return ret; + rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, + start ? 0x10 : 0x00, 0x10); + if (rc < 0) + return rc; + + if (!start) { + /* disable video capture */ + rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1); + return rc; + } + /* enable video capture */ - return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1); + rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + + if (dev->mode == EM28XX_ANALOG_MODE) + rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1); + else + rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1); + + msleep(6); + + return rc; } int em28xx_outfmt_set_yuv422(struct em28xx *dev) { - em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1); - em28xx_write_regs(dev, VINMODE_REG, "\x10", 1); - return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1); + em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1); + em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1); + return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1); } static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin, u8 ymax) { - em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax); + em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", + xmin, ymin, xmax, ymax); - em28xx_write_regs(dev, XMIN_REG, &xmin, 1); - em28xx_write_regs(dev, XMAX_REG, &xmax, 1); - em28xx_write_regs(dev, YMIN_REG, &ymin, 1); - return em28xx_write_regs(dev, YMAX_REG, &ymax, 1); + em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); + em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); + em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); + return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); } static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, @@ -349,34 +411,36 @@ static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, u8 cheight = height; u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01); - em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7), + em28xx_coredbg("em28xx Area Set: (%d,%d)\n", + (width | (overflow & 2) << 7), (height | (overflow & 1) << 8)); - em28xx_write_regs(dev, HSTART_REG, &hstart, 1); - em28xx_write_regs(dev, VSTART_REG, &vstart, 1); - em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1); - em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1); - return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1); + em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); + em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); + em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); + em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); + return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); } static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) { u8 mode; /* the em2800 scaler only supports scaling down to 50% */ - if(dev->is_em2800) + if (dev->is_em2800) mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); else { u8 buf[2]; buf[0] = h; buf[1] = h >> 8; - em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2); + em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); buf[0] = v; buf[1] = v >> 8; - em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2); - /* it seems that both H and V scalers must be active to work correctly */ + em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); + /* it seems that both H and V scalers must be active + to work correctly */ mode = (h || v)? 0x30: 0x00; } - return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30); + return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); } /* FIXME: this only function read values from dev */ @@ -426,10 +490,246 @@ int em28xx_set_alternate(struct em28xx *dev) dev->alt, dev->max_pkt_size); errCode = usb_set_interface(dev->udev, 0, dev->alt); if (errCode < 0) { - em28xx_errdev ("cannot change alternate number to %d (error=%i)\n", + em28xx_errdev("cannot change alternate number to %d (error=%i)\n", dev->alt, errCode); return errCode; } } return 0; } + +int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) +{ + int rc = 0; + + if (!gpio) + return rc; + + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + if (dev->mode == EM28XX_ANALOG_MODE) + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + else + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1); + msleep(6); + + /* Send GPIO reset sequences specified at board entry */ + while (gpio->sleep >= 0) { + if (gpio->reg >= 0) { + rc = em28xx_write_reg_bits(dev, + gpio->reg, + gpio->val, + gpio->mask); + if (rc < 0) + return rc; + } + if (gpio->sleep > 0) + msleep(gpio->sleep); + + gpio++; + } + return rc; +} + +int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) +{ + if (dev->mode == set_mode) + return 0; + + if (set_mode == EM28XX_MODE_UNDEFINED) { + dev->mode = set_mode; + return 0; + } + +#if 0 + /* Resource is locked */ + if (dev->mode != EM28XX_MODE_UNDEFINED) + return -EINVAL; +#endif + dev->mode = set_mode; + + if (dev->mode == EM28XX_DIGITAL_MODE) + return em28xx_gpio_set(dev, dev->digital_gpio); + else + return em28xx_gpio_set(dev, dev->analog_gpio); +} +EXPORT_SYMBOL_GPL(em28xx_set_mode); + +/* ------------------------------------------------------------------ + URB control + ------------------------------------------------------------------*/ + +/* + * IRQ callback, called by URB callback + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs) +#else +static void em28xx_irq_callback(struct urb *urb) +#endif +{ + struct em28xx_dmaqueue *dma_q = urb->context; + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + int rc, i; + + /* Copy data from URB */ + spin_lock(&dev->slock); + rc = dev->isoc_ctl.isoc_copy(dev, urb); + spin_unlock(&dev->slock); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + em28xx_isocdbg("urb resubmit failed (error=%i)\n", + urb->status); + } +} + +/* + * Stop and Deallocate URBs + */ +void em28xx_uninit_isoc(struct em28xx *dev) +{ + struct urb *urb; + int i; + + em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); + + dev->isoc_ctl.nfields = -1; + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + usb_kill_urb(urb); + usb_unlink_urb(urb); + if (dev->isoc_ctl.transfer_buffer[i]) { + usb_buffer_free(dev->udev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + dev->isoc_ctl.num_bufs = 0; + + em28xx_capture_start(dev, 0); +} +EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); + +/* + * Allocate URBs and start IRQ + */ +int em28xx_init_isoc(struct em28xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) +{ + struct em28xx_dmaqueue *dma_q = &dev->vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; + int rc; + + em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); + + /* De-allocates all pending stuff */ + em28xx_uninit_isoc(dev); + + dev->isoc_ctl.isoc_copy = isoc_copy; + dev->isoc_ctl.num_bufs = num_bufs; + + dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + em28xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + em28xx_errdev("cannot allocate memory for usbtransfer\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + dev->isoc_ctl.max_pkt_size = max_pkt_size; + dev->isoc_ctl.buf = NULL; + + sb_size = max_packets * dev->isoc_ctl.max_pkt_size; + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + + dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!dev->isoc_ctl.transfer_buffer[i]) { + em28xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt()?" while in int":""); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + /* FIXME: this is a hack - should be + 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' + should also be using 'desc.bInterval' + */ + pipe = usb_rcvisocpipe(dev->udev, + dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); + + usb_fill_int_urb(urb, dev->udev, pipe, + dev->isoc_ctl.transfer_buffer[i], sb_size, + em28xx_irq_callback, dma_q, 1); + + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP; + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->isoc_ctl.max_pkt_size; + k += dev->isoc_ctl.max_pkt_size; + } + } + + init_waitqueue_head(&dma_q->wq); + + em28xx_capture_start(dev, 1); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + em28xx_err("submit of urb %i failed (error=%i)\n", i, + rc); + em28xx_uninit_isoc(dev); + return rc; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(em28xx_init_isoc); diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c new file mode 100644 index 000000000..5c9941d92 --- /dev/null +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -0,0 +1,506 @@ +/* + DVB device driver for em28xx + + (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + + (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> + - Fixes for the driver to properly work with HVR-950 + + (c) 2008 Aidan Thornton <makosoft@googlemail.com> + + Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: + (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> + (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] + + 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. + */ + +#include <linux/kernel.h> +#include <linux/usb.h> +#include "compat.h" + +#include "em28xx.h" +#include <media/v4l2-common.h> +#include <media/videobuf-vmalloc.h> + +#include "lgdt330x.h" +#include "zl10353.h" + +MODULE_DESCRIPTION("driver for em28xx based DVB cards"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ +} while (0) + +#define EM28XX_DVB_NUM_BUFS 5 +#define EM28XX_DVB_MAX_PACKETSIZE 564 +#define EM28XX_DVB_MAX_PACKETS 64 + +struct em28xx_dvb { + struct dvb_frontend *frontend; + + /* feed count management */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) + struct mutex lock; +#else + struct semaphore lock; +#endif + int nfeeds; + + /* general boilerplate stuff */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + struct dvb_adapter adapter; +#else + struct dvb_adapter *adapter; +#endif + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; +}; + + +static inline void print_err_status(struct em28xx *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + dprintk(1, "URB status %d [%s].\n", status, errmsg); + } else { + dprintk(1, "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) +{ + int i; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + + return 0; +} + +static int start_streaming(struct em28xx_dvb *dvb) +{ + int rc; + struct em28xx *dev = dvb->adapter.priv; + + usb_set_interface(dev->udev, 0, 1); + rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + if (rc < 0) + return rc; + + return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, + EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE, + dvb_isoc_copy); +} + +static int stop_streaming(struct em28xx_dvb *dvb) +{ + struct em28xx *dev = dvb->adapter.priv; + + em28xx_uninit_isoc(dev); + + em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + + return 0; +} + +static int start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct em28xx_dvb *dvb = demux->priv; + int rc, ret; + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&dvb->lock); + dvb->nfeeds++; + rc = dvb->nfeeds; + + if (dvb->nfeeds == 1) { + ret = start_streaming(dvb); + if (ret < 0) + rc = ret; + } + + mutex_unlock(&dvb->lock); + return rc; +} + +static int stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct em28xx_dvb *dvb = demux->priv; + int err = 0; + + mutex_lock(&dvb->lock); + dvb->nfeeds--; + + if (0 == dvb->nfeeds) + err = stop_streaming(dvb); + + mutex_unlock(&dvb->lock); + return err; +} + + + +/* ------------------------------------------------------------------ */ +static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct em28xx *dev = fe->dvb->priv; + + if (acquire) + return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + else + return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); +} + +/* ------------------------------------------------------------------ */ + +static struct lgdt330x_config em2880_lgdt3303_dev = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, +}; + +static struct zl10353_config em28xx_zl10353_with_xc3028 = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .parallel_ts = 1, + .if2 = 45600, +}; + +/* ------------------------------------------------------------------ */ + +static int attach_xc3028(u8 addr, struct em28xx *dev) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.i2c_adap = &dev->i2c_adap; + cfg.i2c_addr = addr; + cfg.callback = em28xx_tuner_callback; + + if (!dev->dvb->frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc3028\n", + dev->name); + return -EINVAL; + } + + fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc3028 attach failed\n", + dev->name); + dvb_frontend_detach(dev->dvb->frontend); + dvb_unregister_frontend(dev->dvb->frontend); + dev->dvb->frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +int register_dvb(struct em28xx_dvb *dvb, + struct module *module, + struct em28xx *dev, + struct device *device) +{ + int result; + + mutex_init(&dvb->lock); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, + adapter_nr); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", + dev->name, result); + goto fail_adapter; + } + + /* Ensure all frontends negotiate bus access */ + dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb->adapter.priv = dev; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); +#else + dvb->adapter->priv = dev; + + /* register frontend */ + result = dvb_register_frontend(dvb->adapter, dvb->frontend); +#endif + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dvb; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = start_feed; + dvb->demux.stop_feed = stop_feed; + + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); +#else + result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter); +#endif + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + dev->name, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + dev->name, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_fe_conn; + } + + /* register network adapter */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); +#else + dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx); +#endif + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_unregister_adapter(&dvb->adapter); +#else + dvb_unregister_adapter(dvb->adapter); +#endif +fail_adapter: + return result; +} + +static void unregister_dvb(struct em28xx_dvb *dvb) +{ + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)) + dvb_unregister_adapter(&dvb->adapter); +#else + dvb_unregister_adapter(dvb->adapter); +#endif +} + + +static int dvb_init(struct em28xx *dev) +{ + int result = 0; + struct em28xx_dvb *dvb; + + dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); + + if (dvb == NULL) { + printk(KERN_INFO "em28xx_dvb: memory allocation failed\n"); + return -ENOMEM; + } + dev->dvb = dvb; + + em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + /* init frontend */ + switch (dev->model) { + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + dvb->frontend = dvb_attach(lgdt330x_attach, + &em2880_lgdt3303_dev, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + dvb->frontend = dvb_attach(zl10353_attach, + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + default: + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" + " isn't supported yet\n", + dev->name); + break; + } + if (NULL == dvb->frontend) { + printk(KERN_ERR + "%s/2: frontend initialization failed\n", + dev->name); + result = -EINVAL; + goto out_free; + } + + /* register everything */ + result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + + if (result < 0) + goto out_free; + + em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + printk(KERN_INFO "Successfully loaded em28xx-dvb\n"); + return 0; + +out_free: + em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + kfree(dvb); + dev->dvb = NULL; + return result; +} + +static int dvb_fini(struct em28xx *dev) +{ + if (dev->dvb) { + unregister_dvb(dev->dvb); + dev->dvb = NULL; + } + + return 0; +} + +static struct em28xx_ops dvb_ops = { + .id = EM28XX_DVB, + .name = "Em28xx dvb Extension", + .init = dvb_init, + .fini = dvb_fini, +}; + +static int __init em28xx_dvb_register(void) +{ + return em28xx_register_extension(&dvb_ops); +} + +static void __exit em28xx_dvb_unregister(void) +{ + em28xx_unregister_extension(&dvb_ops); +} + +module_init(em28xx_dvb_register); +module_exit(em28xx_dvb_unregister); diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index f1e52e5d1..c22e73019 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -41,11 +41,21 @@ static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); -#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\ - printk(fmt, ##args); } while (0) -#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__ , ##args); } while (0) + +#define dprintk1(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(fmt, ##args); \ + } \ +} while (0) + +#define dprintk2(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(KERN_DEBUG "%s at %s: " fmt, \ + dev->name, __func__ , ##args); \ + } \ +} while (0) /* * em2800_i2c_send_max4() @@ -235,16 +245,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return 0; for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; - dprintk2(2,"%s %s addr=%x len=%d:", + dprintk2(2, "%s %s addr=%x len=%d:", (msgs[i].flags & I2C_M_RD) ? "read" : "write", i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (!msgs[i].len) { /* no len: check only for device presence */ + if (!msgs[i].len) { /* no len: check only for device presence */ if (dev->is_em2800) rc = em2800_i2c_check_for_device(dev, addr); else rc = em28xx_i2c_check_for_device(dev, addr); if (rc < 0) { - dprintk2(2," no device\n"); + dprintk2(2, " no device\n"); return rc; } @@ -258,14 +268,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, rc = em28xx_i2c_recv_bytes(dev, addr, msgs[i].buf, msgs[i].len); - if (i2c_debug>=2) { - for (byte = 0; byte < msgs[i].len; byte++) { + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) printk(" %02x", msgs[i].buf[byte]); - } } } else { /* write bytes */ - if (i2c_debug>=2) { + if (i2c_debug >= 2) { for (byte = 0; byte < msgs[i].len; byte++) printk(" %02x", msgs[i].buf[byte]); } @@ -281,13 +290,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, } if (rc < 0) goto err; - if (i2c_debug>=2) + if (i2c_debug >= 2) printk("\n"); } return num; - err: - dprintk2(2," ERROR: %i\n", rc); +err: + dprintk2(2, " ERROR: %i\n", rc); return rc; } @@ -330,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) return -1; buf = 0; - if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) { + + err = i2c_master_send(&dev->i2c_client, &buf, 1); + if (err != 1) { printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", dev->name, err); return -1; @@ -403,8 +414,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) break; } printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - em_eeprom->string_idx_table,em_eeprom->string1, - em_eeprom->string2,em_eeprom->string3); + em_eeprom->string_idx_table, + em_eeprom->string1, + em_eeprom->string2, + em_eeprom->string3); return 0; } @@ -441,58 +454,61 @@ static int attach_inform(struct i2c_client *client) struct em28xx *dev = client->adapter->algo_data; switch (client->addr << 1) { - case 0x86: - case 0x84: - case 0x96: - case 0x94: - { - struct v4l2_priv_tun_config tda9887_cfg; - - struct tuner_setup tun_setup; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = TUNER_TDA9887; - tun_setup.addr = client->addr; - - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); - break; - } - case 0x42: - dprintk1(1,"attach_inform: saa7114 detected.\n"); - break; - case 0x4a: - dprintk1(1,"attach_inform: saa7113 detected.\n"); - break; - case 0xa0: - dprintk1(1,"attach_inform: eeprom detected.\n"); - break; - case 0x60: - case 0x8e: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys); - em28xx_set_ir(dev,ir); - break; - } - case 0x80: - case 0x88: - dprintk1(1,"attach_inform: msp34xx detected.\n"); - break; - case 0xb8: - case 0xba: - dprintk1(1,"attach_inform: tvp5150 detected.\n"); - break; + case 0x86: + case 0x84: + case 0x96: + case 0x94: + { + struct v4l2_priv_tun_config tda9887_cfg; + + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = TUNER_TDA9887; + tun_setup.addr = client->addr; + + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, + &tun_setup); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); + break; + } + case 0x42: + dprintk1(1, "attach_inform: saa7114 detected.\n"); + break; + case 0x4a: + dprintk1(1, "attach_inform: saa7113 detected.\n"); + break; + case 0xa0: + dprintk1(1, "attach_inform: eeprom detected.\n"); + break; + case 0x60: + case 0x8e: + { + struct IR_i2c *ir = i2c_get_clientdata(client); + dprintk1(1, "attach_inform: IR detected (%s).\n", + ir->phys); + em28xx_set_ir(dev, ir); + break; + } + case 0x80: + case 0x88: + dprintk1(1, "attach_inform: msp34xx detected.\n"); + break; + case 0xb8: + case 0xba: + dprintk1(1, "attach_inform: tvp5150 detected.\n"); + break; - default: - if (!dev->tuner_addr) - dev->tuner_addr = client->addr; + default: + if (!dev->tuner_addr) + dev->tuner_addr = client->addr; - dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); + dprintk1(1, "attach inform: detected I2C address %x\n", + client->addr << 1); } @@ -522,7 +538,7 @@ static struct i2c_adapter em28xx_adap_template = { static struct i2c_client em28xx_client_template = { .name = "em28xx internal", -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15) .flags = I2C_CLIENT_ALLOW_USE, #endif }; diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 5c78eceff..49c40f083 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -33,10 +33,12 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) +#define dprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + } /* ----------------------------------------------------------------------- */ @@ -45,7 +47,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(&ir->c, &b, 1)) { dprintk("read error\n"); return -EIO; } @@ -75,29 +77,30 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char code; /* poll IR chip */ - if (2 != i2c_master_recv(&ir->c,buf,2)) + if (2 != i2c_master_recv(&ir->c, buf, 2)) return -EIO; /* Does eliminate repeated parity code */ - if (buf[1]==0xff) + if (buf[1] == 0xff) return 0; #if 0 /* avoid reapeating keystrokes */ - if (buf[1]==ir->old) + if (buf[1] == ir->old) return 0; #endif - ir->old=buf[1]; + ir->old = buf[1]; /* Rearranges bits to the right order */ - code= ((buf[0]&0x01)<<5) | /* 0010 0000 */ + code = ((buf[0]&0x01)<<5) | /* 0010 0000 */ ((buf[0]&0x02)<<3) | /* 0001 0000 */ ((buf[0]&0x04)<<1) | /* 0000 1000 */ ((buf[0]&0x08)>>1) | /* 0000 0100 */ ((buf[0]&0x10)>>3) | /* 0000 0010 */ ((buf[0]&0x20)>>5); /* 0000 0001 */ - dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]); + dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", + code, buf[0]); /* return key */ *ir_key = code; @@ -112,15 +115,14 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* poll IR chip */ - if (3 != i2c_master_recv(&ir->c,buf,3)) { + if (3 != i2c_master_recv(&ir->c, buf, 3)) { dprintk("read error\n"); return -EIO; } dprintk("key %02x\n", buf[2]&0x3f); - if (buf[0]!=0x00){ + if (buf[0] != 0x00) return 0; - } *ir_key = buf[2]&0x3f; *ir_raw = buf[2]&0x3f; diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h new file mode 100644 index 000000000..9058bed07 --- /dev/null +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -0,0 +1,88 @@ +#define EM_GPIO_0 (1 << 0) +#define EM_GPIO_1 (1 << 1) +#define EM_GPIO_2 (1 << 2) +#define EM_GPIO_3 (1 << 3) +#define EM_GPIO_4 (1 << 4) +#define EM_GPIO_5 (1 << 5) +#define EM_GPIO_6 (1 << 6) +#define EM_GPIO_7 (1 << 7) + +#define EM_GPO_0 (1 << 0) +#define EM_GPO_1 (1 << 1) +#define EM_GPO_2 (1 << 2) +#define EM_GPO_3 (1 << 3) + +/* em2800 registers */ +#define EM2800_R08_AUDIOSRC 0x08 + +/* em28xx registers */ + + /* GPIO/GPO registers */ +#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ +#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ + +#define EM28XX_R06_I2C_CLK 0x06 +#define EM28XX_R0A_CHIPID 0x0a +#define EM28XX_R0C_USBSUSP 0x0c /* */ + +#define EM28XX_R0E_AUDIOSRC 0x0e +#define EM28XX_R0F_XCLK 0x0f + +#define EM28XX_R10_VINMODE 0x10 +#define EM28XX_R11_VINCTRL 0x11 +#define EM28XX_R12_VINENABLE 0x12 /* */ + +#define EM28XX_R14_GAMMA 0x14 +#define EM28XX_R15_RGAIN 0x15 +#define EM28XX_R16_GGAIN 0x16 +#define EM28XX_R17_BGAIN 0x17 +#define EM28XX_R18_ROFFSET 0x18 +#define EM28XX_R19_GOFFSET 0x19 +#define EM28XX_R1A_BOFFSET 0x1a + +#define EM28XX_R1B_OFLOW 0x1b +#define EM28XX_R1C_HSTART 0x1c +#define EM28XX_R1D_VSTART 0x1d +#define EM28XX_R1E_CWIDTH 0x1e +#define EM28XX_R1F_CHEIGHT 0x1f + +#define EM28XX_R20_YGAIN 0x20 +#define EM28XX_R21_YOFFSET 0x21 +#define EM28XX_R22_UVGAIN 0x22 +#define EM28XX_R23_UOFFSET 0x23 +#define EM28XX_R24_VOFFSET 0x24 +#define EM28XX_R25_SHARPNESS 0x25 + +#define EM28XX_R26_COMPR 0x26 +#define EM28XX_R27_OUTFMT 0x27 + +#define EM28XX_R28_XMIN 0x28 +#define EM28XX_R29_XMAX 0x29 +#define EM28XX_R2A_YMIN 0x2a +#define EM28XX_R2B_YMAX 0x2b + +#define EM28XX_R30_HSCALELOW 0x30 +#define EM28XX_R31_HSCALEHIGH 0x31 +#define EM28XX_R32_VSCALELOW 0x32 +#define EM28XX_R33_VSCALEHIGH 0x33 + +#define EM28XX_R40_AC97LSB 0x40 +#define EM28XX_R41_AC97MSB 0x41 +#define EM28XX_R42_AC97ADDR 0x42 +#define EM28XX_R43_AC97BUSY 0x43 + +/* em202 registers */ +#define EM28XX_R02_MASTER_AC97 0x02 +#define EM28XX_R10_LINE_IN_AC97 0x10 +#define EM28XX_R14_VIDEO_AC97 0x14 + +/* register settings */ +#define EM2800_AUDIO_SRC_TUNER 0x0d +#define EM2800_AUDIO_SRC_LINE 0x0c +#define EM28XX_AUDIO_SRC_TUNER 0xc0 +#define EM28XX_AUDIO_SRC_LINE 0x80 + +/* FIXME: Need to be populated with the other chip ID's */ +enum em28xx_chip_id { + CHIP_ID_EM2883 = 36, +}; diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 924f29214..093fef4bb 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1,5 +1,6 @@ /* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> Markus Rechberger <mrechberger@gmail.com> @@ -33,7 +34,7 @@ #include <linux/i2c.h> #include <linux/version.h> #include <linux/mm.h> -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) #include <linux/mutex.h> #endif @@ -41,7 +42,7 @@ #include <media/v4l2-common.h> #include <media/msp3400.h> #include <media/tuner.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) #include "i2c-compat.h" #endif @@ -63,14 +64,13 @@ static unsigned int isoc_debug; module_param(isoc_debug, int, 0644); MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); -#define em28xx_isocdbg(fmt, arg...) do {\ - if (isoc_debug) \ +#define em28xx_isocdbg(fmt, arg...) \ +do {\ + if (isoc_debug) { \ printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -/* Limits minimum and default number of buffers */ -#define EM28XX_MIN_BUF 4 -#define EM28XX_DEF_BUF 8 + dev->name, __func__ , ##arg); \ + } \ + } while (0) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -83,13 +83,13 @@ static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) MODULE_PARM(card, "1-" __stringify(EM28XX_MAXBOARDS) "i"); MODULE_PARM(video_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i"); MODULE_PARM(vbi_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i"); MODULE_PARM(radio_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i"); #else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) static int dummy; module_param_array(card, int, dummy, 0444); module_param_array(video_nr, int, dummy, 0444); @@ -108,8 +108,8 @@ MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug; -module_param(video_debug,int,0644); -MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; @@ -126,7 +126,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { .step = 0x1, .default_value = 0x1f, .flags = 0, - },{ + }, { .id = V4L2_CID_AUDIO_MUTE, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Mute", @@ -313,11 +313,10 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, /* * Controls the isoc copy of each urb packet */ -static inline int em28xx_isoc_copy(struct urb *urb) +static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) { struct em28xx_buffer *buf; struct em28xx_dmaqueue *dma_q = urb->context; - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); unsigned char *outp = NULL; int i, len = 0, rc = 1; unsigned char *p; @@ -399,192 +398,6 @@ static inline int em28xx_isoc_copy(struct urb *urb) } /* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ - -/* - * IRQ callback, called by URB callback - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs) -#else -static void em28xx_irq_callback(struct urb *urb) -#endif -{ - struct em28xx_dmaqueue *dma_q = urb->context; - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); - int rc, i; - - /* Copy data from URB */ - spin_lock(&dev->slock); - rc = em28xx_isoc_copy(urb); - spin_unlock(&dev->slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - em28xx_err("urb resubmit failed (error=%i)\n", - urb->status); - } -} - -/* - * Stop and Deallocate URBs - */ -static void em28xx_uninit_isoc(struct em28xx *dev) -{ - struct urb *urb; - int i; - - em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); - - dev->isoc_ctl.nfields = -1; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_buffer_free(dev->udev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - - dev->isoc_ctl.num_bufs = 0; - - em28xx_capture_start(dev, 0); -} - -/* - * Allocate URBs and start IRQ - */ -static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets, - int num_bufs) -{ - struct em28xx_dmaqueue *dma_q = &dev->vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; - - em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); - - /* De-allocates all pending stuff */ - em28xx_uninit_isoc(dev); - - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - em28xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - em28xx_errdev("cannot allocate memory for usbtransfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dev->isoc_ctl.max_pkt_size = dev->max_pkt_size; - dev->isoc_ctl.buf = NULL; - - sb_size = max_packets * dev->isoc_ctl.max_pkt_size; - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt()?" while in int":""); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - /* FIXME: this is a hack - should be - 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' - should also be using 'desc.bInterval' - */ - pipe = usb_rcvisocpipe(dev->udev, 0x82); - usb_fill_int_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - em28xx_irq_callback, dma_q, 1); - - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; - - k = 0; - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->isoc_ctl.max_pkt_size; - k += dev->isoc_ctl.max_pkt_size; - } - } - - return 0; -} - -static int em28xx_start_thread(struct em28xx_dmaqueue *dma_q) -{ - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); - int i, rc = 0; - - em28xx_videodbg("Called em28xx_start_thread\n"); - - init_waitqueue_head(&dma_q->wq); - - em28xx_capture_start(dev, 1); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - em28xx_err("submit of urb %i failed (error=%i)\n", i, - rc); - em28xx_uninit_isoc(dev); - return rc; - } - } - - if (rc < 0) - return rc; - - return 0; -} - -/* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ @@ -592,6 +405,8 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + struct v4l2_frequency f; *size = 16 * fh->dev->width * fh->dev->height >> 3; if (0 == *count) @@ -600,6 +415,12 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) if (*count < EM28XX_MIN_BUF) *count = EM28XX_MIN_BUF; + /* Ask tuner to go to analog mode */ + memset(&f, 0, sizeof(f)); + f.frequency = dev->ctl_freq; + + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); + return 0; } @@ -637,7 +458,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, struct em28xx_fh *fh = vq->priv_data; struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); struct em28xx *dev = fh->dev; - struct em28xx_dmaqueue *vidq = &dev->vidq; int rc = 0, urb_init = 0; /* FIXME: It assumes depth = 16 */ @@ -661,12 +481,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, urb_init = 1; if (urb_init) { - rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS); - if (rc < 0) - goto fail; - - rc = em28xx_start_thread(vidq); + rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS, dev->max_pkt_size, + em28xx_isoc_copy); if (rc < 0) goto fail; } @@ -692,7 +509,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) { struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); struct em28xx_fh *fh = vq->priv_data; @@ -710,7 +528,7 @@ static struct videobuf_queue_ops em28xx_video_qops = { .buf_release = buffer_release, }; -/********************* v4l2 interface ******************************************/ +/********************* v4l2 interface **************************************/ /* * em28xx_config() @@ -726,9 +544,9 @@ static int em28xx_config(struct em28xx *dev) #if 1 /* enable vbi capturing */ -/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */ -/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */ - em28xx_write_regs_req(dev,0x00,0x11,"\x51",1); +/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */ +/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */ + em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1); #endif dev->mute = 1; /* maybe not the right place... */ @@ -768,12 +586,15 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); if (dev->has_msp34xx) { - if (dev->i2s_speed) - em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); + if (dev->i2s_speed) { + em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, + &dev->i2s_speed); + } route.input = dev->ctl_ainput; route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); /* Note: this is msp3400 specific */ - em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); + em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, + &route); } em28xx_audio_analog_set(dev); @@ -1013,7 +834,7 @@ out: return rc; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1130,11 +951,11 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) index = dev->ctl_ainput; - if (index == 0) { + if (index == 0) strcpy(a->name, "Television"); - } else { + else strcpy(a->name, "Line In"); - } + a->capability = V4L2_AUDCAP_STEREO; a->index = index; @@ -1345,9 +1166,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int em28xx_reg_len(int reg) { switch (reg) { - case AC97LSB_REG: - case HSCALELOW_REG: - case VSCALELOW_REG: + case EM28XX_R40_AC97LSB: + case EM28XX_R30_HSCALELOW: + case EM28XX_R32_VSCALELOW: return 2; default: return 1; @@ -1749,7 +1570,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { int minor = iminor(inode); int errCode = 0, radio = 0; - struct em28xx *h,*dev = NULL; + struct em28xx *h, *dev = NULL; struct em28xx_fh *fh; enum v4l2_buf_type fh_type = 0; @@ -1774,8 +1595,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_videodbg("open minor=%d type=%s users=%d\n", minor, v4l2_type_names[fh_type], dev->users); - fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); +#if 0 + errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + if (errCode < 0) { + em28xx_errdev("Device locked on digital mode. Can't open analog\n"); + return -EBUSY; + } +#endif + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); return -ENOMEM; @@ -1792,9 +1620,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev->hscale = 0; dev->vscale = 0; + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); em28xx_set_alternate(dev); em28xx_resolution_set(dev); + /* Needed, since GPIO might have disabled power of + some i2c device + */ + em28xx_config_i2c(dev); + #if 0 /* device needs to be initialized before isoc transfer */ video_mux(dev, 0); @@ -1815,6 +1649,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); + return errCode; } @@ -1857,12 +1692,13 @@ static void em28xx_release_resources(struct em28xx *dev) usb_put_dev(dev->udev); /* Mark device as unused */ - em28xx_devused&=~(1<<dev->devno); + em28xx_devused &= ~(1<<dev->devno); } /* * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls + * stops streaming and deallocates all resources allocated by the v4l2 + * calls and ioctls */ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) { @@ -1893,6 +1729,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) /* do this before setting alternate! */ em28xx_uninit_isoc(dev); + em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); /* set alternate 0 */ dev->alt = 0; @@ -1915,7 +1752,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) * will allocate buffers when called for the first time */ static ssize_t -em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, +em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct em28xx_fh *fh = filp->private_data; @@ -2089,7 +1926,7 @@ static struct video_device em28xx_radio_template = { #endif }; -/******************************** usb interface *****************************************/ +/******************************** usb interface ******************************/ static LIST_HEAD(em28xx_extension_devlist); @@ -2184,10 +2021,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - errCode = em28xx_read_reg(dev, CHIPID_REG); - if (errCode >= 0) - em28xx_info("em28xx chip ID = %d\n", errCode); - em28xx_pre_card_setup(dev); errCode = em28xx_config(dev); @@ -2331,6 +2164,9 @@ static void request_module_async(struct work_struct *work) request_module("snd-usb-audio"); else request_module("em28xx-alsa"); + + if (dev->has_dvb) + request_module("em28xx-dvb"); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) @@ -2369,22 +2205,24 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum = interface->altsetting[0].desc.bInterfaceNumber; /* Check to see next free device and mark as used */ - nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS); - em28xx_devused|=1<<nr; + nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); + em28xx_devused |= 1<<nr; /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor,udev->descriptor.idProduct, + udev->descriptor.idVendor, + udev->descriptor.idProduct, ifnum, interface->altsetting[0].desc.bInterfaceClass); - em28xx_devused&=~(1<<nr); + em28xx_devused &= ~(1<<nr); return -ENODEV; } em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor,udev->descriptor.idProduct, + udev->descriptor.idVendor, + udev->descriptor.idProduct, ifnum, interface->altsetting[0].desc.bInterfaceClass); @@ -2394,18 +2232,19 @@ static int em28xx_usb_probe(struct usb_interface *interface, if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); - em28xx_devused&=~(1<<nr); + em28xx_devused &= ~(1<<nr); return -ENODEV; } if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); - em28xx_devused&=~(1<<nr); + em28xx_devused &= ~(1<<nr); return -ENODEV; } if (nr >= EM28XX_MAXBOARDS) { - printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); - em28xx_devused&=~(1<<nr); + printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + em28xx_devused &= ~(1<<nr); return -ENOMEM; } @@ -2413,7 +2252,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { em28xx_err(DRIVER_NAME ": out of memory!\n"); - em28xx_devused&=~(1<<nr); + em28xx_devused &= ~(1<<nr); return -ENOMEM; } @@ -2437,14 +2276,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; - dev->num_alt=uif->num_altsetting; - em28xx_info("Alternate settings: %i\n",dev->num_alt); -// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* - dev->alt_max_pkt_size = kmalloc(32* - dev->num_alt,GFP_KERNEL); + dev->num_alt = uif->num_altsetting; + em28xx_info("Alternate settings: %i\n", dev->num_alt); +/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */ + dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); + if (dev->alt_max_pkt_size == NULL) { em28xx_errdev("out of memory!\n"); - em28xx_devused&=~(1<<nr); + em28xx_devused &= ~(1<<nr); kfree(dev); return -ENOMEM; } @@ -2454,11 +2293,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, wMaxPacketSize); dev->alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - em28xx_info("Alternate setting %i, max size= %i\n",i, - dev->alt_max_pkt_size[i]); + em28xx_info("Alternate setting %i, max size= %i\n", i, + dev->alt_max_pkt_size[i]); } - if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) + if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) dev->model = card[nr]; /* allocate device struct */ @@ -2494,7 +2333,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_info("disconnecting %s\n", dev->vdev->name); - /* wait until all current v4l2 io is finished then deallocate resources */ + /* wait until all current v4l2 io is finished then deallocate + resources */ mutex_lock(&dev->lock); wake_up_interruptible_all(&dev->open); @@ -2531,7 +2371,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) } static struct usb_driver em28xx_usb_driver = { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15) .owner = THIS_MODULE, #endif .name = "em28xx", diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index cf6efe070..d31d11a5e 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -30,10 +30,38 @@ #include <media/videobuf-vmalloc.h> #include <linux/i2c.h> -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) #include <linux/mutex.h> #endif #include <media/ir-kbd-i2c.h> +#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) +#include <media/videobuf-dvb.h> +#endif +#include "tuner-xc2028.h" +#include "em28xx-reg.h" + +/* Boards supported by driver */ +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 + +/* Limits minimum and default number of buffers */ +#define EM28XX_MIN_BUF 4 +#define EM28XX_DEF_BUF 8 /* maximum number of em28xx boards */ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ @@ -84,12 +112,20 @@ /* time in msecs to wait for i2c writes to finish */ #define EM2800_I2C_WRITE_TIMEOUT 20 +enum em28xx_mode { + EM28XX_MODE_UNDEFINED, + EM28XX_ANALOG_MODE, + EM28XX_DIGITAL_MODE, +}; + enum em28xx_stream_state { STREAM_OFF, STREAM_INTERRUPT, STREAM_ON, }; +struct em28xx; + struct em28xx_usb_isoc_ctl { /* max packet size of isoc transaction */ int max_pkt_size; @@ -119,6 +155,10 @@ struct em28xx_usb_isoc_ctl { /* Stores the number of received fields */ int nfields; + + /* isoc urb callback */ + int (*isoc_copy) (struct em28xx *dev, struct urb *urb); + }; struct em28xx_fmt { @@ -190,6 +230,12 @@ enum em28xx_decoder { EM28XX_SAA7114 }; +struct em28xx_reg_seq { + int reg; + unsigned char val, mask; + int sleep; +}; + struct em28xx_board { char *name; int vchannels; @@ -203,8 +249,7 @@ struct em28xx_board { unsigned int mts_firmware:1; unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; - - unsigned int analog_gpio; + unsigned int has_dvb:1; enum em28xx_decoder decoder; @@ -237,7 +282,10 @@ enum em28xx_dev_state { #define EM28XX_NUM_AUDIO_PACKETS 64 #define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ #define EM28XX_CAPTURE_STREAM_EN 1 + +/* em28xx extensions */ #define EM28XX_AUDIO 0x10 +#define EM28XX_DVB 0x20 struct em28xx_audio { char name[50]; @@ -263,13 +311,24 @@ struct em28xx_audio { spinlock_t slock; }; +struct em28xx; + +struct em28xx_fh { + struct em28xx *dev; + unsigned int stream_on:1; /* Locks streams */ + int radio; + + struct videobuf_queue vb_vidq; + + enum v4l2_buf_type type; +}; + /* main device struct */ struct em28xx { /* generic device properties */ char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ - unsigned int analog_gpio; unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; @@ -277,6 +336,16 @@ struct em28xx { unsigned int has_audio_class:1; unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; + unsigned int has_dvb:1; + + /* Some older em28xx chips needs a waiting time after writing */ + unsigned int wait_after_write; + + /* GPIO sequences for analog and digital mode */ + struct em28xx_reg_seq *analog_gpio, *digital_gpio; + + /* GPIO sequences for tuner callbacks */ + struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio; int video_inputs; /* number of video inputs */ struct list_head devlist; @@ -309,7 +378,8 @@ struct em28xx { unsigned int video_bytesread; /* Number of bytes read */ unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ + unsigned long i2c_hash; /* i2c devicelist hash - + for boards with generic ID */ struct em28xx_audio *adev; @@ -320,7 +390,7 @@ struct em28xx { struct work_struct request_module_wk; /* locks */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) struct mutex lock; #else struct semaphore lock, fileop_lock; @@ -347,24 +417,21 @@ struct em28xx { struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ /* helper funcs that call usb_control_msg */ - int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf, - int len); - int (*em28xx_read_reg) (struct em28xx * dev, u16 reg); - int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg, + int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, + char *buf, int len); + int (*em28xx_read_reg) (struct em28xx *dev, u16 reg); + int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg, char *buf, int len); - int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg, + int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg, char *buf, int len); - int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg); -}; + int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg); -struct em28xx_fh { - struct em28xx *dev; - unsigned int stream_on:1; /* Locks streams */ - int radio; + enum em28xx_mode mode; - struct videobuf_queue vb_vidq; + /* Caches GPO and GPIO registers */ + unsigned char reg_gpo, reg_gpio; - enum v4l2_buf_type type; + struct em28xx_dvb *dvb; }; struct em28xx_ops { @@ -402,19 +469,26 @@ int em28xx_capture_start(struct em28xx *dev, int start); int em28xx_outfmt_set_yuv422(struct em28xx *dev); int em28xx_resolution_set(struct em28xx *dev); int em28xx_set_alternate(struct em28xx *dev); +int em28xx_init_isoc(struct em28xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); +void em28xx_uninit_isoc(struct em28xx *dev); +int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); +int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); /* Provided by em28xx-video.c */ int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); /* Provided by em28xx-cards.c */ -extern int em2800_variant_detect(struct usb_device* udev,int model); +extern int em2800_variant_detect(struct usb_device *udev, int model); extern void em28xx_pre_card_setup(struct em28xx *dev); extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); +int em28xx_tuner_callback(void *ptr, int command, int arg); /* Provided by em28xx-input.c */ /* TODO: Check if the standard get_key handlers on ir-common can be used */ @@ -423,71 +497,6 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -/* em2800 registers */ -#define EM2800_AUDIOSRC_REG 0x08 - -/* em28xx registers */ -#define I2C_CLK_REG 0x06 -#define CHIPID_REG 0x0a -#define USBSUSP_REG 0x0c /* */ - -#define AUDIOSRC_REG 0x0e -#define XCLK_REG 0x0f - -#define VINMODE_REG 0x10 -#define VINCTRL_REG 0x11 -#define VINENABLE_REG 0x12 /* */ - -#define GAMMA_REG 0x14 -#define RGAIN_REG 0x15 -#define GGAIN_REG 0x16 -#define BGAIN_REG 0x17 -#define ROFFSET_REG 0x18 -#define GOFFSET_REG 0x19 -#define BOFFSET_REG 0x1a - -#define OFLOW_REG 0x1b -#define HSTART_REG 0x1c -#define VSTART_REG 0x1d -#define CWIDTH_REG 0x1e -#define CHEIGHT_REG 0x1f - -#define YGAIN_REG 0x20 -#define YOFFSET_REG 0x21 -#define UVGAIN_REG 0x22 -#define UOFFSET_REG 0x23 -#define VOFFSET_REG 0x24 -#define SHARPNESS_REG 0x25 - -#define COMPR_REG 0x26 -#define OUTFMT_REG 0x27 - -#define XMIN_REG 0x28 -#define XMAX_REG 0x29 -#define YMIN_REG 0x2a -#define YMAX_REG 0x2b - -#define HSCALELOW_REG 0x30 -#define HSCALEHIGH_REG 0x31 -#define VSCALELOW_REG 0x32 -#define VSCALEHIGH_REG 0x33 - -#define AC97LSB_REG 0x40 -#define AC97MSB_REG 0x41 -#define AC97ADDR_REG 0x42 -#define AC97BUSY_REG 0x43 - -/* em202 registers */ -#define MASTER_AC97 0x02 -#define LINE_IN_AC97 0x10 -#define VIDEO_AC97 0x14 - -/* register settings */ -#define EM2800_AUDIO_SRC_TUNER 0x0d -#define EM2800_AUDIO_SRC_LINE 0x0c -#define EM28XX_AUDIO_SRC_TUNER 0xc0 -#define EM28XX_AUDIO_SRC_LINE 0x80 - /* printk macros */ #define em28xx_err(fmt, arg...) do {\ @@ -504,80 +513,80 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, printk(KERN_WARNING "%s: "fmt,\ dev->name , ##arg); } while (0) -inline static int em28xx_compression_disable(struct em28xx *dev) +static inline int em28xx_compression_disable(struct em28xx *dev) { /* side effect of disabling scaler and mixer */ - return em28xx_write_regs(dev, COMPR_REG, "\x00", 1); + return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1); } -inline static int em28xx_contrast_get(struct em28xx *dev) +static inline int em28xx_contrast_get(struct em28xx *dev) { - return em28xx_read_reg(dev, YGAIN_REG) & 0x1f; + return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f; } -inline static int em28xx_brightness_get(struct em28xx *dev) +static inline int em28xx_brightness_get(struct em28xx *dev) { - return em28xx_read_reg(dev, YOFFSET_REG); + return em28xx_read_reg(dev, EM28XX_R21_YOFFSET); } -inline static int em28xx_saturation_get(struct em28xx *dev) +static inline int em28xx_saturation_get(struct em28xx *dev) { - return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f; + return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f; } -inline static int em28xx_u_balance_get(struct em28xx *dev) +static inline int em28xx_u_balance_get(struct em28xx *dev) { - return em28xx_read_reg(dev, UOFFSET_REG); + return em28xx_read_reg(dev, EM28XX_R23_UOFFSET); } -inline static int em28xx_v_balance_get(struct em28xx *dev) +static inline int em28xx_v_balance_get(struct em28xx *dev) { - return em28xx_read_reg(dev, VOFFSET_REG); + return em28xx_read_reg(dev, EM28XX_R24_VOFFSET); } -inline static int em28xx_gamma_get(struct em28xx *dev) +static inline int em28xx_gamma_get(struct em28xx *dev) { - return em28xx_read_reg(dev, GAMMA_REG) & 0x3f; + return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f; } -inline static int em28xx_contrast_set(struct em28xx *dev, s32 val) +static inline int em28xx_contrast_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1); } -inline static int em28xx_brightness_set(struct em28xx *dev, s32 val) +static inline int em28xx_brightness_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1); } -inline static int em28xx_saturation_set(struct em28xx *dev, s32 val) +static inline int em28xx_saturation_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1); } -inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val) +static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1); } -inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val) +static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1); } -inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) +static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) { u8 tmp = (u8) val; - return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1); + return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1); } /*FIXME: maxw should be dependent of alt mode */ -inline static unsigned int norm_maxw(struct em28xx *dev) +static inline unsigned int norm_maxw(struct em28xx *dev) { if (dev->max_range_640_480) return 640; @@ -585,7 +594,7 @@ inline static unsigned int norm_maxw(struct em28xx *dev) return 720; } -inline static unsigned int norm_maxh(struct em28xx *dev) +static inline unsigned int norm_maxh(struct em28xx *dev) { if (dev->max_range_640_480) return 480; diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index d949a8133..a7640c49f 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -219,7 +219,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, /* Process pending program info updates and pending VBI data */ ivtv_update_pgm_info(itv); - if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) { + if (time_after(jiffies, + itv->dualwatch_jiffies + + msecs_to_jiffies(1000))) { itv->dualwatch_jiffies = jiffies; ivtv_dualwatch(itv); } diff --git a/linux/drivers/media/video/ivtv/ivtv-mailbox.c b/linux/drivers/media/video/ivtv/ivtv-mailbox.c index 13a6c374d..1b5c0ac09 100644 --- a/linux/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/linux/drivers/media/video/ivtv/ivtv-mailbox.c @@ -177,7 +177,8 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f /* Sleep before a retry, if not atomic */ if (!(flags & API_NO_WAIT_MB)) { - if (jiffies - then > msecs_to_jiffies(10*retries)) + if (time_after(jiffies, + then + msecs_to_jiffies(10*retries))) break; ivtv_msleep_timeout(10, 0); } @@ -244,7 +245,9 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) data, then just return 0 as there is no need to issue this command again. Just an optimization to prevent unnecessary use of mailboxes. */ if (itv->api_cache[cmd].last_jiffies && - jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) && + time_before(jiffies, + itv->api_cache[cmd].last_jiffies + + msecs_to_jiffies(1800000)) && !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { itv->api_cache[cmd].last_jiffies = jiffies; return 0; @@ -299,7 +302,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) } } while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { - if (jiffies - then > api_timeout) { + if (time_after(jiffies, then + api_timeout)) { IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); /* reset the mailbox, but it is likely too late already */ write_sync(0, &mbox->flags); @@ -311,7 +314,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) else ivtv_msleep_timeout(1, 0); } - if (jiffies - then > msecs_to_jiffies(100)) + if (time_after(jiffies, then + msecs_to_jiffies(100))) IVTV_DEBUG_WARN("%s took %u jiffies\n", api_info[cmd].name, jiffies_to_msecs(jiffies - then)); diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 24d98ecf3..4ab8d3683 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -768,7 +768,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* wait 2s for EOS interrupt */ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && - jiffies < then + msecs_to_jiffies (2000)) { + time_before(jiffies, + then + msecs_to_jiffies(2000))) { schedule_timeout(msecs_to_jiffies(10)); } diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index ef780ed60..716f30eb5 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -410,7 +410,7 @@ int msp_sleep(struct msp_state *state, int timeout) } /* ------------------------------------------------------------------------ */ -#ifdef CONFIG_VIDEO_V4L1 +#ifdef CONFIG_VIDEO_ALLOW_V4L1 static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) { if (rxsubchans == V4L2_TUNER_SUB_MONO) @@ -558,7 +558,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ -#ifdef CONFIG_VIDEO_V4L1 +#ifdef CONFIG_VIDEO_ALLOW_V4L1 case VIDIOCGAUDIO: { struct video_audio *va = arg; diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index 97cc92c82..bf2462a58 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -222,9 +222,8 @@ static int mxb_probe(struct saa7146_dev* dev) device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients); /* check if all devices are present */ - if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c - || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) { - + if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || + !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { printk("mxb: did not find all i2c devices. aborting\n"); i2c_del_adapter(&mxb->i2c_adapter); kfree(mxb); diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c index cba851d18..4c8050667 100644 --- a/linux/drivers/media/video/ov511.c +++ b/linux/drivers/media/video/ov511.c @@ -5838,7 +5838,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); - ov->vdev->dev = &dev->dev; + ov->vdev->dev = &intf->dev; video_set_drvdata(ov->vdev, ov); for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c index 32e43e9d1..8b500528d 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c @@ -68,7 +68,7 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val) int ret = 0; if (!cptr) return -EINVAL; LOCK_TAKE(cptr->hdw->big_lock); do { - if (cptr->info->set_value != 0) { + if (cptr->info->set_value) { if (cptr->info->type == pvr2_ctl_bitmask) { mask &= cptr->info->def.type_bitmask.valid_bits; } else if ((cptr->info->type == pvr2_ctl_int)|| @@ -269,7 +269,7 @@ unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr) int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr) { if (!cptr) return 0; - return cptr->info->set_value != 0; + return cptr->info->set_value != NULL; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 77edc72a2..8356bc0e4 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2357,7 +2357,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; - if (cptr->info->is_dirty == 0) continue; + if (!cptr->info->is_dirty) continue; if (!cptr->info->is_dirty(cptr)) continue; commit_flag = !0; @@ -2706,7 +2706,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, u16 address; unsigned int pipe; LOCK_TAKE(hdw->big_lock); do { - if ((hdw->fw_buffer == 0) == !enable_flag) break; + if ((hdw->fw_buffer == NULL) == !enable_flag) break; if (!enable_flag) { pvr2_trace(PVR2_TRACE_FIRMWARE, @@ -2775,7 +2775,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, /* Return true if we're in a mode for retrieval CPU firmware */ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) { - return hdw->fw_buffer != 0; + return hdw->fw_buffer != NULL; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c index 7b3be67f5..e4aae2c97 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -603,7 +603,7 @@ void pvr2_stream_kill(struct pvr2_stream *sp) struct pvr2_buffer *bp; mutex_lock(&sp->mutex); do { pvr2_stream_internal_flush(sp); - while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) { + while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { pvr2_buffer_set_idle(bp); } if (sp->buffer_total_count != sp->buffer_target_count) { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c index aef12fecb..d7bbbe00f 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c @@ -174,7 +174,7 @@ static int pvr2_ioread_start(struct pvr2_ioread *cp) if (!(cp->stream)) return 0; pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); - while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) { + while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) { stat = pvr2_buffer_queue(bp); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index 6a7db17ba..8236b2b2d 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -929,7 +929,7 @@ static void pwc_iso_stop(struct pwc_device *pdev) struct urb *urb; urb = pdev->sbuf[i].urb; - if (urb != 0) { + if (urb) { PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); usb_kill_urb(urb); } @@ -945,7 +945,7 @@ static void pwc_iso_free(struct pwc_device *pdev) struct urb *urb; urb = pdev->sbuf[i].urb; - if (urb != 0) { + if (urb) { PWC_DEBUG_MEMORY("Freeing URB\n"); usb_free_urb(urb); pdev->sbuf[i].urb = NULL; @@ -1784,8 +1784,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* Allocate video_device structure */ pdev->vdev = video_device_alloc(); - if (pdev->vdev == 0) - { + if (!pdev->vdev) { PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); kfree(pdev); return -ENOMEM; diff --git a/linux/drivers/media/video/saa7110.c b/linux/drivers/media/video/saa7110.c index eb561ce6c..0692e4bef 100644 --- a/linux/drivers/media/video/saa7110.c +++ b/linux/drivers/media/video/saa7110.c @@ -489,7 +489,7 @@ saa7110_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; @@ -497,7 +497,7 @@ saa7110_detect_client (struct i2c_adapter *adapter, strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client))); decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL); - if (decoder == 0) { + if (!decoder) { kfree(client); return -ENOMEM; } diff --git a/linux/drivers/media/video/saa7111.c b/linux/drivers/media/video/saa7111.c index df44aed92..917fb2553 100644 --- a/linux/drivers/media/video/saa7111.c +++ b/linux/drivers/media/video/saa7111.c @@ -503,7 +503,7 @@ saa7111_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/saa7114.c b/linux/drivers/media/video/saa7114.c index ebf42cf9e..158bd123c 100644 --- a/linux/drivers/media/video/saa7114.c +++ b/linux/drivers/media/video/saa7114.c @@ -842,7 +842,7 @@ saa7114_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c index 030d07dd6..bdae62189 100644 --- a/linux/drivers/media/video/saa717x.c +++ b/linux/drivers/media/video/saa717x.c @@ -1529,7 +1529,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, #endif }; - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) EXPORT_NO_SYMBOLS; #endif diff --git a/linux/drivers/media/video/saa7185.c b/linux/drivers/media/video/saa7185.c index 2ac144d9a..7a6c9c1fb 100644 --- a/linux/drivers/media/video/saa7185.c +++ b/linux/drivers/media/video/saa7185.c @@ -404,7 +404,7 @@ saa7185_detect_client (struct i2c_adapter *adapter, return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; client->adapter = adapter; diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c index 72b6f476c..c41e50ba6 100644 --- a/linux/drivers/media/video/tda9840.c +++ b/linux/drivers/media/video/tda9840.c @@ -181,7 +181,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind) /* allocate memory for client structure */ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (0 == client) { + if (!client) { printk("not enough kernel memory\n"); return -ENOMEM; } diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c index 363b5be2c..16f369195 100644 --- a/linux/drivers/media/video/tea6415c.c +++ b/linux/drivers/media/video/tea6415c.c @@ -73,7 +73,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind) /* allocate memory for client structure */ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (0 == client) { + if (!client) { return -ENOMEM; } diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c index 0e3e039f2..7a8fec9cf 100644 --- a/linux/drivers/media/video/tea6420.c +++ b/linux/drivers/media/video/tea6420.c @@ -110,7 +110,7 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) /* allocate memory for client structure */ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (0 == client) { + if (!client) { return -ENOMEM; } diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index 38a90afb6..fa218e910 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -802,7 +802,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (analog_ops->standby) analog_ops->standby(&t->fe); break; -#ifdef CONFIG_VIDEO_V4L1 +#ifdef CONFIG_VIDEO_ALLOW_V4L1 case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) return 0; diff --git a/linux/drivers/media/video/tuner-xc2028-types.h b/linux/drivers/media/video/tuner-xc2028-types.h index d0057fbf0..e38970f1c 100644 --- a/linux/drivers/media/video/tuner-xc2028-types.h +++ b/linux/drivers/media/video/tuner-xc2028-types.h @@ -1,6 +1,9 @@ /* tuner-xc2028_types * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This file includes internal tipes to be used inside tuner-xc2028. + * Shouldn't be included outside tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) * This code is placed under the terms of the GNU General Public License v2 */ @@ -85,11 +88,28 @@ /* This flag identifies that the scode table has a new format */ #define HAS_IF (1 << 30) -#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ +#if 0 +/* The current seek algorithm doesn'use those flags. Instead, this is + currently useful only for debug process, since this is a HINT table + associating an alias to an IF table that can be used by that digital + video standard (in the case of DTV6/7/78/8, QAM and ATSC), or to a + particular demod type + */ +#define SCODE_TYPES (DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) +#else +#define SCODE_TYPES SCODE +#endif -/* Newer types to be moved to videodev2.h */ + +/* Newer types not defined on videodev2.h. + The original idea were to move all those types to videodev2.h, but + it seemed overkill, since, with the exception of SECAM/K3, the other + types seem to be autodetected. + It is not clear where secam/k3 is used, nor we have a feedback of this + working or being autodetected by the standard secam firmware. + */ #define V4L2_STD_SECAM_K3 (0x04000000) diff --git a/linux/drivers/media/video/tuner-xc2028.c b/linux/drivers/media/video/tuner-xc2028.c index b333b911c..ce066dc97 100644 --- a/linux/drivers/media/video/tuner-xc2028.c +++ b/linux/drivers/media/video/tuner-xc2028.c @@ -1,6 +1,6 @@ /* tuner-xc2028 * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) * * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) * - frontend interface @@ -145,7 +145,7 @@ struct xc2028_data { _rc; \ }) -static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) +static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) { unsigned char buf[2]; unsigned char ibuf[2]; @@ -250,6 +250,7 @@ static v4l2_std_id parse_audio_std_option(void) static void free_firmware(struct xc2028_data *priv) { int i; + tuner_dbg("%s called\n", __func__); if (!priv->firm) return; @@ -418,7 +419,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; int i, best_i = -1, best_nr_matches = 0; - unsigned int ign_firm_type_mask = 0; + unsigned int type_mask = 0; tuner_dbg("%s called, want type=", __func__); if (debug) { @@ -435,18 +436,23 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, *id = V4L2_STD_PAL; if (type & BASE) - type &= BASE_TYPES; + type_mask = BASE_TYPES; else if (type & SCODE) { type &= SCODE_TYPES; - ign_firm_type_mask = HAS_IF; + type_mask = SCODE_TYPES &~ HAS_IF; } else if (type & DTV_TYPES) - type &= DTV_TYPES; + type_mask = DTV_TYPES; else if (type & STD_SPECIFIC_TYPES) - type &= STD_SPECIFIC_TYPES; + type_mask = STD_SPECIFIC_TYPES; + + type &= type_mask; + + if (!type & SCODE) + type_mask = ~0; /* Seek for exact match */ for (i = 0; i < priv->firm_size; i++) { - if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) && + if ((type == (priv->firm[i].type & type_mask)) && (*id == priv->firm[i].id)) goto found; } @@ -456,7 +462,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id match_mask; int nr_matches; - if (type != (priv->firm[i].type & ~ign_firm_type_mask)) + if (type != (priv->firm[i].type & type_mask)) continue; match_mask = *id & priv->firm[i].id; @@ -793,10 +799,10 @@ check_device: goto fail; } - tuner_info("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, - (version & 0xf0) >> 4, version & 0xf); + tuner_dbg("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); /* Check firmware version against what we downloaded. */ if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { @@ -1065,6 +1071,10 @@ static int xc2028_set_params(struct dvb_frontend *fe, T_DIGITAL_TV, type, 0, demod); } +#if 0 +/* This is needed at sleep (S1/S3), but not at fe_standby. Otherwise, + firmware will be loaded on every open() + */ static int xc2028_sleep(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; @@ -1085,7 +1095,7 @@ static int xc2028_sleep(struct dvb_frontend *fe) return rc; } - +#endif static int xc2028_dvb_release(struct dvb_frontend *fe) { @@ -1133,21 +1143,21 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) mutex_lock(&priv->lock); - kfree(priv->ctrl.fname); - free_firmware(priv); - memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - priv->ctrl.fname = NULL; + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; if (p->fname) { + if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { + kfree(priv->ctrl.fname); + free_firmware(priv); + } + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); if (priv->ctrl.fname == NULL) rc = -ENOMEM; } - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - mutex_unlock(&priv->lock); return rc; @@ -1167,8 +1177,9 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .get_frequency = xc2028_get_frequency, .get_rf_strength = xc2028_signal, .set_params = xc2028_set_params, +#if 0 .sleep = xc2028_sleep, - +#endif #if 0 int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); int (*get_status)(struct dvb_frontend *fe, u32 *status); diff --git a/linux/drivers/media/video/tuner-xc2028.h b/linux/drivers/media/video/tuner-xc2028.h index 612e49063..fc2f132a5 100644 --- a/linux/drivers/media/video/tuner-xc2028.h +++ b/linux/drivers/media/video/tuner-xc2028.h @@ -1,6 +1,6 @@ /* tuner-xc2028 * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) * This code is placed under the terms of the GNU General Public License v2 */ @@ -12,7 +12,7 @@ #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" /* Dmoduler IF (kHz) */ -#define XC3028_FE_DEFAULT 0 +#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ #define XC3028_FE_LG60 6000 #define XC3028_FE_ATI638 6380 #define XC3028_FE_OREN538 5380 diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c index e6907db8b..7dc6623cc 100644 --- a/linux/drivers/media/video/tvp5150.c +++ b/linux/drivers/media/video/tvp5150.c @@ -1175,12 +1175,12 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, return 0; c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (c == 0) + if (!c) return -ENOMEM; memcpy(c, &client_template, sizeof(struct i2c_client)); core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL); - if (core == 0) { + if (!core) { kfree(c); return -ENOMEM; } diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c index 1261593cf..1afbcc147 100644 --- a/linux/drivers/media/video/usbvideo/ibmcam.c +++ b/linux/drivers/media/video/usbvideo/ibmcam.c @@ -802,6 +802,21 @@ static enum ParseState ibmcam_model2_320x240_parse_lines( return scan_Continue; } +/* + * ibmcam_model3_parse_lines() + * + * | Even lines | Odd Lines | + * -----------------------------------| + * |YYY........Y|UYVYUYVY.........UYVY| + * |YYY........Y|UYVYUYVY.........UYVY| + * |............|.....................| + * |YYY........Y|UYVYUYVY.........UYVY| + * |------------+---------------------| + * + * There is one (U, V) chroma pair for every four luma (Y) values. This + * function reads a pair of lines at a time and obtains missing chroma values + * from adjacent pixels. + */ static enum ParseState ibmcam_model3_parse_lines( struct uvd *uvd, struct usbvideo_frame *frame, @@ -816,6 +831,7 @@ static enum ParseState ibmcam_model3_parse_lines( const int ccm = 128; /* Color correction median - see below */ int i, u, v, rw, data_w=0, data_h=0, color_corr; static unsigned char lineBuffer[640*3]; + int line; color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); @@ -869,15 +885,15 @@ static enum ParseState ibmcam_model3_parse_lines( return scan_NextFrame; } - /* Make sure there's enough data for the entire line */ - len = 3 * data_w; /* <y-data> <uv-data> */ + /* Make sure that lineBuffer can store two lines of data */ + len = 3 * data_w; /* <y-data> <uyvy-data> */ assert(len <= sizeof(lineBuffer)); - /* Make sure there's enough data for the entire line */ + /* Make sure there's enough data for two lines */ if (RingQueue_GetLength(&uvd->dp) < len) return scan_Out; - /* Suck one line out of the ring queue */ + /* Suck two lines of data out of the ring queue */ RingQueue_Dequeue(&uvd->dp, lineBuffer, len); data = lineBuffer; @@ -887,15 +903,23 @@ static enum ParseState ibmcam_model3_parse_lines( rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1; RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1); - for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { - int y, rv, gv, bv; /* RGB components */ + /* Iterate over two lines. */ + for (line = 0; line < 2; line++) { + for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { + int y; + int rv, gv, bv; /* RGB components */ - if (i < data_w) { - y = data[i]; /* Luminosity is the first line */ + if (i >= data_w) { + RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0); + continue; + } + + /* first line is YYY...Y; second is UYVY...UYVY */ + y = data[(line == 0) ? i : (i*2 + 1)]; /* Apply static color correction */ - u = color[i*2] + hue_corr; - v = color[i*2 + 1] + hue2_corr; + u = color[(i/2)*4] + hue_corr; + v = color[(i/2)*4 + 2] + hue2_corr; /* Apply color correction */ if (color_corr != 0) { @@ -903,13 +927,21 @@ static enum ParseState ibmcam_model3_parse_lines( u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; } - } else - y = 0, u = v = 128; - YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); - RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */ + + YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); + RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* No deinterlacing */ + } + + /* Check for the end of requested data */ + if (rw == 0) + break; + + /* Prepare for the second line */ + rw--; + data = lineBuffer + data_w; } - frame->deinterlace = Deinterlace_FillEvenLines; + frame->deinterlace = Deinterlace_None; /* * Account for number of bytes that we wrote into output V4L frame. diff --git a/linux/drivers/media/video/videocodec.c b/linux/drivers/media/video/videocodec.c index b30b6b2a9..cf24956f3 100644 --- a/linux/drivers/media/video/videocodec.c +++ b/linux/drivers/media/video/videocodec.c @@ -39,6 +39,7 @@ #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <asm/uaccess.h> #endif @@ -320,56 +321,22 @@ videocodec_unregister (const struct videocodec *codec) } #ifdef CONFIG_PROC_FS -/* ============ */ -/* procfs stuff */ -/* ============ */ - -static char *videocodec_buf = NULL; -static int videocodec_bufsize; - -static int -videocodec_build_table (void) +static int proc_videocodecs_show(struct seq_file *m, void *v) { struct codec_list *h = codeclist_top; struct attached_list *a; - int i = 0, size; - - // sum up amount of slaves plus their attached masters - while (h) { - i += h->attached + 1; - h = h->next; - } -#define LINESIZE 100 - size = LINESIZE * (i + 1); - dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i, - size); - - kfree(videocodec_buf); - videocodec_buf = kmalloc(size, GFP_KERNEL); - - if (!videocodec_buf) - return 0; - - i = 0; - i += scnprintf(videocodec_buf + i, size - 1, - "<S>lave or attached <M>aster name type flags magic "); - i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n"); + seq_printf(m, "<S>lave or attached <M>aster name type flags magic "); + seq_printf(m, "(connected as)\n"); h = codeclist_top; while (h) { - if (i > (size - LINESIZE)) - break; // security check - i += scnprintf(videocodec_buf + i, size -i -1, - "S %32s %04x %08lx %08lx (TEMPLATE)\n", + seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", h->codec->name, h->codec->type, h->codec->flags, h->codec->magic); a = h->list; while (a) { - if (i > (size - LINESIZE)) - break; // security check - i += scnprintf(videocodec_buf + i, size -i -1, - "M %32s %04x %08lx %08lx (%s)\n", + seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n", a->codec->master_data->name, a->codec->master_data->type, a->codec->master_data->flags, @@ -380,54 +347,21 @@ videocodec_build_table (void) h = h->next; } - return i; + return 0; } -//The definition: -//typedef int (read_proc_t)(char *page, char **start, off_t off, -// int count, int *eof, void *data); - -static int -videocodec_info (char *buffer, - char **buffer_location, - off_t offset, - int buffer_length, - int *eof, - void *data) +static int proc_videocodecs_open(struct inode *inode, struct file *file) { - int size; - - dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n", - offset, buffer_length, videocodec_bufsize); - - if (offset == 0) { - videocodec_bufsize = videocodec_build_table(); - } - if ((offset < 0) || (offset >= videocodec_bufsize)) { - dprintk(4, - "videocodec_info: call delivers no result, return 0\n"); - *eof = 1; - return 0; - } - - if (buffer_length < (videocodec_bufsize - offset)) { - dprintk(4, "videocodec_info: %ld needed, %d got\n", - videocodec_bufsize - offset, buffer_length); - size = buffer_length; - } else { - dprintk(4, "videocodec_info: last reading of %ld bytes\n", - videocodec_bufsize - offset); - size = videocodec_bufsize - offset; - *eof = 1; - } - - memcpy(buffer, videocodec_buf + offset, size); - /* doesn't work... */ - /* copy_to_user(buffer, videocodec_buf+offset, size); */ - /* *buffer_location = videocodec_buf+offset; */ - - return size; + return single_open(file, proc_videocodecs_show, NULL); } + +static const struct file_operations videocodecs_proc_fops = { + .owner = THIS_MODULE, + .open = proc_videocodecs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif /* ===================== */ @@ -444,16 +378,8 @@ videocodec_init (void) VIDEOCODEC_VERSION); #ifdef CONFIG_PROC_FS - videocodec_buf = NULL; - videocodec_bufsize = 0; - - videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL); - if (videocodec_proc_entry) { - videocodec_proc_entry->read_proc = videocodec_info; - videocodec_proc_entry->write_proc = NULL; - videocodec_proc_entry->data = NULL; - videocodec_proc_entry->owner = THIS_MODULE; - } else { + videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops); + if (!videocodec_proc_entry) { dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); } #endif @@ -465,7 +391,6 @@ videocodec_exit (void) { #ifdef CONFIG_PROC_FS remove_proc_entry("videocodecs", NULL); - kfree(videocodec_buf); #endif } diff --git a/linux/drivers/media/video/zoran.h b/linux/drivers/media/video/zoran.h index 848dbcf25..5f74688c1 100644 --- a/linux/drivers/media/video/zoran.h +++ b/linux/drivers/media/video/zoran.h @@ -243,10 +243,8 @@ struct zoran_format { #ifdef CONFIG_VIDEO_V4L1_COMPAT int palette; #endif -#ifdef CONFIG_VIDEO_V4L2 __u32 fourcc; int colorspace; -#endif int depth; __u32 flags; __u32 vfespfr; @@ -271,20 +269,6 @@ struct zoran_v4l_settings { const struct zoran_format *format; /* capture format */ }; -/* whoops, this one is undeclared if !v4l2 */ -#ifndef CONFIG_VIDEO_V4L2 -struct v4l2_jpegcompression { - int quality; - int APPn; - int APP_len; - char APP_data[60]; - int COM_len; - char COM_data[60]; - __u32 jpeg_markers; - __u8 reserved[116]; -}; -#endif - /* jpg-capture/-playback settings */ struct zoran_jpg_settings { int decimation; /* this bit is used to set everything to default */ diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c index aede0b584..6b7a7c137 100644 --- a/linux/drivers/media/video/zoran_driver.c +++ b/linux/drivers/media/video/zoran_driver.c @@ -88,7 +88,6 @@ #include "zoran_device.h" #include "zoran_card.h" -#ifdef CONFIG_VIDEO_V4L2 /* we declare some card type definitions here, they mean * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */ #define ZORAN_V4L2_VID_FLAGS ( \ @@ -97,19 +96,15 @@ V4L2_CAP_VIDEO_OUTPUT |\ V4L2_CAP_VIDEO_OVERLAY \ ) -#endif #include <asm/byteorder.h> -#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT) +#if defined(CONFIG_VIDEO_V4L1_COMPAT) #define ZFMT(pal, fcc, cs) \ .palette = (pal), .fourcc = (fcc), .colorspace = (cs) -#elif defined(CONFIG_VIDEO_V4L2) -#define ZFMT(pal, fcc, cs) \ - .fourcc = (fcc), .colorspace = (cs) #else #define ZFMT(pal, fcc, cs) \ - .palette = (pal) + .fourcc = (fcc), .colorspace = (cs) #endif const struct zoran_format zoran_formats[] = { @@ -219,7 +214,6 @@ static int lock_norm; /* 0 = default 1 = Don't change TV standard (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 * we calculate the nearest higher power-of-two, which * will be the recommended buffersize */ @@ -242,7 +236,6 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings) return 8192; return result; } -#endif /* forward references */ static void v4l_fbuffer_free(struct file *file); @@ -353,7 +346,7 @@ v4l_fbuffer_alloc (struct file *file) /* Use kmalloc */ mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); - if (mem == 0) { + if (!mem) { dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n", @@ -1776,7 +1769,6 @@ setup_overlay (struct file *file, return wait_grab_pending(zr); } -#ifdef CONFIG_VIDEO_V4L2 /* get the status of a buffer in the clients buffer queue */ static int zoran_v4l2_buffer_status (struct file *file, @@ -1882,7 +1874,6 @@ zoran_v4l2_buffer_status (struct file *file, return 0; } -#endif static int zoran_set_norm (struct zoran *zr, @@ -2691,8 +2682,6 @@ zoran_do_ioctl (struct inode *inode, } break; -#ifdef CONFIG_VIDEO_V4L2 - /* The new video4linux2 capture interface - much nicer than video4linux1, since * it allows for integrating the JPEG capturing calls inside standard v4l2 */ @@ -4264,7 +4253,6 @@ zoran_do_ioctl (struct inode *inode, return 0; } break; -#endif default: dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n", @@ -4724,9 +4712,7 @@ static const struct file_operations zoran_fops = { struct video_device zoran_template __devinitdata = { .name = ZORAN_NAME, .type = ZORAN_VID_TYPE, -#ifdef CONFIG_VIDEO_V4L2 .type2 = ZORAN_V4L2_VID_FLAGS, -#endif .fops = &zoran_fops, .release = &zoran_vdev_release, .minor = -1 diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index 0afd1c9c1..c2abb3af9 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -395,7 +395,7 @@ static int read_frame(struct zr364xx_camera *cam, int framenum) } -static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt, +static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt, loff_t * ppos) { unsigned long count = cnt; |