aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb/au0828
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/au0828')
-rw-r--r--drivers/media/usb/au0828/Kconfig17
-rw-r--r--drivers/media/usb/au0828/Makefile6
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c47
-rw-r--r--drivers/media/usb/au0828/au0828-core.c73
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c169
-rw-r--r--drivers/media/usb/au0828/au0828-i2c.c13
-rw-r--r--drivers/media/usb/au0828/au0828-video.c343
-rw-r--r--drivers/media/usb/au0828/au0828.h17
8 files changed, 458 insertions, 227 deletions
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
index 1766c0ce93b..953a37c613b 100644
--- a/drivers/media/usb/au0828/Kconfig
+++ b/drivers/media/usb/au0828/Kconfig
@@ -1,17 +1,28 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+ depends on I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select VIDEOBUF_VMALLOC
select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT
- select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
---help---
- This is a video4linux driver for Auvitek's USB device.
+ This is a hybrid analog/digital tv capture driver for
+ Auvitek's AU0828 USB device.
To compile this driver as a module, choose M here: the
module will be called au0828
+
+config VIDEO_AU0828_V4L2
+ bool "Auvitek AU0828 v4l2 analog video support"
+ depends on VIDEO_AU0828 && VIDEO_V4L2
+ select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
+ default y
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+ Choose Y here to include support for v4l2 analog video
+ capture within the au0828 driver.
diff --git a/drivers/media/usb/au0828/Makefile b/drivers/media/usb/au0828/Makefile
index 98cc20cc0ff..be3bdf69802 100644
--- a/drivers/media/usb/au0828/Makefile
+++ b/drivers/media/usb/au0828/Makefile
@@ -1,4 +1,8 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+ifeq ($(CONFIG_VIDEO_AU0828_V4L2),y)
+ au0828-objs += au0828-video.o au0828-vbi.o
+endif
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index 0cb7c28dcb1..7fdadf9bc90 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -108,7 +108,7 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
@@ -169,7 +169,9 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
- case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72261: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72271: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72281: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
@@ -183,16 +185,15 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
__func__, tv.model);
}
+void au0828_card_analog_fe_setup(struct au0828_dev *dev);
+
void au0828_card_setup(struct au0828_dev *dev)
{
static u8 eeprom[256];
- struct tuner_setup tun_setup;
- struct v4l2_subdev *sd;
- unsigned int mode_mask = T_ANALOG_TV;
dprintk(1, "%s()\n", __func__);
- memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+ dev->board = au0828_boards[dev->boardnr];
if (dev->i2c_rc == 0) {
dev->i2c_client.addr = 0xa0 >> 1;
@@ -209,6 +210,16 @@ void au0828_card_setup(struct au0828_dev *dev)
break;
}
+ au0828_card_analog_fe_setup(dev);
+}
+
+void au0828_card_analog_fe_setup(struct au0828_dev *dev)
+{
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ struct tuner_setup tun_setup;
+ struct v4l2_subdev *sd;
+ unsigned int mode_mask = T_ANALOG_TV;
+
if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
/* Load the analog demodulator driver (note this would need to
be abstracted out if we ever need to support a different
@@ -234,6 +245,7 @@ void au0828_card_setup(struct au0828_dev *dev)
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
&tun_setup);
}
+#endif
}
/*
@@ -258,18 +270,25 @@ void au0828_gpio_setup(struct au0828_dev *dev)
* 9 - XC5000 Tuner
*/
- /* Into reset */
+ /* Set relevant GPIOs as outputs (leave the EEPROM W/P
+ as an input since we will never touch it and it has
+ a pullup) */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+
+ /* Into reset */
au0828_write(dev, REG_001, 0x0);
au0828_write(dev, REG_000, 0x0);
- msleep(100);
+ msleep(50);
- /* Out of reset (leave the cs5340 in reset until needed) */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
- au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+ /* Bring power supply out of reset */
+ au0828_write(dev, REG_000, 0x80);
+ msleep(50);
+
+ /* Bring xc5000 and au8522 out of reset (leave the
+ cs5340 in reset until needed) */
+ au0828_write(dev, REG_001, 0x02); /* xc5000 */
+ au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
msleep(250);
break;
@@ -333,6 +352,8 @@ struct usb_device_id au0828_usb_id_table[] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x7213),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7270),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ },
};
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 745a80a798c..ab45a6f9dcc 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -125,6 +125,26 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
return status;
}
+static void au0828_usb_release(struct au0828_dev *dev)
+{
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ kfree(dev);
+}
+
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct au0828_dev *dev =
+ container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_release(dev);
+}
+#endif
+
static void au0828_usb_disconnect(struct usb_interface *interface)
{
struct au0828_dev *dev = usb_get_intfdata(interface);
@@ -134,28 +154,27 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_unregister(dev);
-
- /* I2C */
- au0828_i2c_unregister(dev);
-
- v4l2_device_unregister(&dev->v4l2_dev);
-
usb_set_intfdata(interface, NULL);
-
mutex_lock(&dev->mutex);
dev->usbdev = NULL;
mutex_unlock(&dev->mutex);
-
- kfree(dev);
-
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ au0828_analog_unregister(dev);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
+ return;
+ }
+#endif
+ au0828_usb_release(dev);
}
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- int ifnum, retval;
+ int ifnum;
+ int retval = 0;
+
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
@@ -194,15 +213,29 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->usbdev = usbdev;
dev->boardnr = id->driver_info;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ dev->v4l2_dev.release = au0828_usb_v4l2_release;
+
/* Create the v4l2_device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
- printk(KERN_ERR "%s() v4l2_device_register failed\n",
+ pr_err("%s() v4l2_device_register failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
+ }
+ /* This control handler will inherit the controls from au8522 */
+ retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
+ if (retval) {
+ pr_err("%s() v4l2_ctrl_handler_init failed\n",
__func__);
mutex_unlock(&dev->lock);
kfree(dev);
- return -EIO;
+ return retval;
}
+ dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
+#endif
/* Power Up the bridge */
au0828_write(dev, REG_600, 1 << 4);
@@ -216,12 +249,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog TV */
if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
au0828_analog_register(dev, interface);
+#endif
/* Digital TV */
- au0828_dvb_register(dev);
+ retval = au0828_dvb_register(dev);
+ if (retval)
+ pr_err("%s() au0282_dev_register failed\n",
+ __func__);
+
/* Store the pointer to the au0828_dev so it can be accessed in
au0828_usb_disconnect */
@@ -232,7 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
mutex_unlock(&dev->lock);
- return 0;
+ return retval;
}
static struct usb_driver au0828_usb_driver = {
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 9a6f15613a3..d8b5d948027 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -33,6 +33,10 @@
#include "mxl5007t.h"
#include "tda18271.h"
+static int preallocate_big_buffers;
+module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644);
+MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define _AU0828_BULKPIPE 0x83
@@ -110,16 +114,20 @@ static void urb_completion(struct urb *purb)
int ptype = usb_pipetype(purb->pipe);
unsigned char *ptr;
- dprintk(2, "%s()\n", __func__);
+ dprintk(2, "%s: %d\n", __func__, purb->actual_length);
- if (!dev)
+ if (!dev) {
+ dprintk(2, "%s: no dev!\n", __func__);
return;
+ }
- if (dev->urb_streaming == 0)
+ if (dev->urb_streaming == 0) {
+ dprintk(2, "%s: not streaming!\n", __func__);
return;
+ }
if (ptype != PIPE_BULK) {
- printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ printk(KERN_ERR "%s: Unsupported URB type %d\n",
__func__, ptype);
return;
}
@@ -153,9 +161,13 @@ static int stop_urb_transfer(struct au0828_dev *dev)
dev->urb_streaming = 0;
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]);
+ if (dev->urbs[i]) {
+ usb_kill_urb(dev->urbs[i]);
+ if (!preallocate_big_buffers)
+ kfree(dev->urbs[i]->transfer_buffer);
+
+ usb_free_urb(dev->urbs[i]);
+ }
}
return 0;
@@ -181,10 +193,18 @@ static int start_urb_transfer(struct au0828_dev *dev)
purb = dev->urbs[i];
- purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+ if (preallocate_big_buffers)
+ purb->transfer_buffer = dev->dig_transfer_buffer[i];
+ else
+ purb->transfer_buffer = kzalloc(URB_BUFSIZE,
+ GFP_KERNEL);
+
if (!purb->transfer_buffer) {
usb_free_urb(purb);
dev->urbs[i] = NULL;
+ printk(KERN_ERR
+ "%s: failed big buffer allocation, err = %d\n",
+ __func__, ret);
goto err;
}
@@ -217,6 +237,25 @@ err:
return ret;
}
+static void au0828_start_transport(struct au0828_dev *dev)
+{
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+
+}
+
+static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
+{
+ if (full_stop) {
+ au0828_write(dev, 0x608, 0x00);
+ au0828_write(dev, 0x609, 0x00);
+ au0828_write(dev, 0x60a, 0x00);
+ }
+ au0828_write(dev, 0x60b, 0x00);
+}
+
static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
@@ -231,13 +270,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
if (dvb) {
mutex_lock(&dvb->lock);
+ dvb->start_count++;
+ dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+ dvb->start_count, dvb->stop_count);
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);
+ au0828_start_transport(dev);
ret = start_urb_transfer(dev);
+ if (ret < 0) {
+ au0828_stop_transport(dev, 0);
+ dvb->feeding--; /* We ran out of memory... */
+ }
}
mutex_unlock(&dvb->lock);
}
@@ -255,11 +298,19 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
dprintk(1, "%s()\n", __func__);
if (dvb) {
+ cancel_work_sync(&dev->restart_streaming);
+
mutex_lock(&dvb->lock);
- if (--dvb->feeding == 0) {
- /* Stop transport */
- ret = stop_urb_transfer(dev);
- au0828_write(dev, 0x60b, 0x00);
+ dvb->stop_count++;
+ dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+ dvb->start_count, dvb->stop_count);
+ if (dvb->feeding > 0) {
+ dvb->feeding--;
+ if (dvb->feeding == 0) {
+ /* Stop transport */
+ ret = stop_urb_transfer(dev);
+ au0828_stop_transport(dev, 0);
+ }
}
mutex_unlock(&dvb->lock);
}
@@ -282,21 +333,50 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
/* Stop transport */
stop_urb_transfer(dev);
- au0828_write(dev, 0x608, 0x00);
- au0828_write(dev, 0x609, 0x00);
- au0828_write(dev, 0x60a, 0x00);
- au0828_write(dev, 0x60b, 0x00);
+ au0828_stop_transport(dev, 1);
/* Start transport */
- au0828_write(dev, 0x608, 0x90);
- au0828_write(dev, 0x609, 0x72);
- au0828_write(dev, 0x60a, 0x71);
- au0828_write(dev, 0x60b, 0x01);
+ au0828_start_transport(dev);
start_urb_transfer(dev);
mutex_unlock(&dvb->lock);
}
+static int au0828_set_frontend(struct dvb_frontend *fe)
+{
+ struct au0828_dev *dev = fe->dvb->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret, was_streaming;
+
+ mutex_lock(&dvb->lock);
+ was_streaming = dev->urb_streaming;
+ if (was_streaming) {
+ au0828_stop_transport(dev, 1);
+
+ /*
+ * We can't hold a mutex here, as the restart_streaming
+ * kthread may also hold it.
+ */
+ mutex_unlock(&dvb->lock);
+ cancel_work_sync(&dev->restart_streaming);
+ mutex_lock(&dvb->lock);
+
+ stop_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+
+ ret = dvb->set_frontend(fe);
+
+ if (was_streaming) {
+ mutex_lock(&dvb->lock);
+ au0828_start_transport(dev);
+ start_urb_transfer(dev);
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
static int dvb_register(struct au0828_dev *dev)
{
struct au0828_dvb *dvb = &dev->dvb;
@@ -304,6 +384,23 @@ static int dvb_register(struct au0828_dev *dev)
dprintk(1, "%s()\n", __func__);
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++) {
+ dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE,
+ GFP_KERNEL);
+
+ if (!dev->dig_transfer_buffer[i]) {
+ result = -ENOMEM;
+
+ printk(KERN_ERR
+ "%s: failed buffer allocation (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_adapter;
+ }
+ }
+ }
+
INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
/* register adapter */
@@ -324,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev)
goto fail_frontend;
}
+ /* Hook dvb frontend */
+ dvb->set_frontend = dvb->frontend->ops.set_frontend;
+ dvb->frontend->ops.set_frontend = au0828_set_frontend;
+
/* register demux stuff */
dvb->demux.dmx.capabilities =
DMX_TS_FILTERING | DMX_SECTION_FILTERING |
@@ -375,6 +476,9 @@ static int dvb_register(struct au0828_dev *dev)
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+
+ dvb->start_count = 0;
+ dvb->stop_count = 0;
return 0;
fail_fe_conn:
@@ -391,6 +495,13 @@ fail_frontend:
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
+
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++)
+ kfree(dev->dig_transfer_buffer[i]);
+ }
+
return result;
}
@@ -403,6 +514,8 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
if (dvb->frontend == NULL)
return;
+ cancel_work_sync(&dev->restart_streaming);
+
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);
@@ -411,6 +524,14 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
+
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++)
+ kfree(dev->dig_transfer_buffer[i]);
+ }
+
+
}
/* All the DVB attach calls go here, this function get's modified
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
index 4ded17fe195..17ec3651b10 100644
--- a/drivers/media/usb/au0828/au0828-i2c.c
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -364,12 +364,9 @@ 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 = au0828_i2c_adap_template;
+ dev->i2c_algo = au0828_i2c_algo_template;
+ dev->i2c_client = au0828_i2c_client_template;
dev->i2c_adap.dev.parent = &dev->usbdev->dev;
@@ -378,7 +375,11 @@ int au0828_i2c_register(struct au0828_dev *dev)
dev->i2c_adap.algo = &dev->i2c_algo;
dev->i2c_adap.algo_data = dev;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+#else
+ i2c_set_adapdata(&dev->i2c_adap, dev);
+#endif
i2c_add_adapter(&dev->i2c_adap);
dev->i2c_client.adapter = &dev->i2c_adap;
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 45387aab10c..9038194513c 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -35,7 +35,7 @@
#include <linux/suspend.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
#include <media/tuner.h>
#include "au0828.h"
#include "au0828-reg.h"
@@ -58,6 +58,12 @@ do {\
} \
} while (0)
+static inline void i2c_gate_ctrl(struct au0828_dev *dev, int val)
+{
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, val);
+}
+
static inline void print_err_status(struct au0828_dev *dev,
int packet, int status)
{
@@ -304,7 +310,7 @@ static inline void buffer_filled(struct au0828_dev *dev,
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dev->isoc_ctl.buf = NULL;
@@ -321,7 +327,7 @@ static inline void vbi_buffer_filled(struct au0828_dev *dev,
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dev->isoc_ctl.vbi_buf = NULL;
@@ -988,20 +994,22 @@ static int au0828_v4l2_open(struct file *filp)
fh->type = type;
fh->dev = dev;
+ v4l2_fh_init(&fh->fh, vdev);
filp->private_data = fh;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (mutex_lock_interruptible(&dev->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ if (dev->users == 0) {
/* set au0828 interface0 to AS5 here again */
ret = usb_set_interface(dev->usbdev, 0, 5);
if (ret < 0) {
+ mutex_unlock(&dev->lock);
printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+ kfree(fh);
return -EBUSY;
}
- dev->width = NTSC_STD_W;
- dev->height = NTSC_STD_H;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->width * dev->height;
- dev->bytesperline = dev->width * 2;
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
@@ -1014,6 +1022,7 @@ static int au0828_v4l2_open(struct file *filp)
}
dev->users++;
+ mutex_unlock(&dev->lock);
videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
NULL, &dev->slock,
@@ -1023,14 +1032,13 @@ static int au0828_v4l2_open(struct file *filp)
&dev->lock);
/* VBI Setup */
- dev->vbi_width = 720;
- dev->vbi_height = 1;
videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct au0828_buffer), fh,
&dev->lock);
+ v4l2_fh_add(&fh->fh);
return ret;
}
@@ -1040,6 +1048,9 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
+ mutex_lock(&dev->lock);
if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
/* Cancel timeout thread in case they didn't call streamoff */
dev->vid_timeout_running = 0;
@@ -1058,19 +1069,14 @@ static int au0828_v4l2_close(struct file *filp)
res_free(fh, AU0828_RESOURCE_VBI);
}
- if (dev->users == 1) {
- if (dev->dev_state & DEV_DISCONNECTED) {
- au0828_analog_unregister(dev);
- kfree(dev);
- return 0;
- }
-
+ if (dev->users == 1 && video_is_registered(video_devdata(filp))) {
au0828_analog_stream_disable(dev);
au0828_uninit_isoc(dev);
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ dev->std_set_in_tuner_core = 0;
/* When close the device, set the usb intf0 into alt0 to free
USB bandwidth */
@@ -1078,6 +1084,7 @@ static int au0828_v4l2_close(struct file *filp)
if (ret < 0)
printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
}
+ mutex_unlock(&dev->lock);
videobuf_mmap_free(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vbiq);
@@ -1087,6 +1094,26 @@ static int au0828_v4l2_close(struct file *filp)
return 0;
}
+/* Must be called with dev->lock held */
+static void au0828_init_tuner(struct au0828_dev *dev)
+{
+ struct v4l2_frequency f = {
+ .frequency = dev->ctrl_freq,
+ .type = V4L2_TUNER_ANALOG_TV,
+ };
+
+ if (dev->std_set_in_tuner_core)
+ return;
+ dev->std_set_in_tuner_core = 1;
+ i2c_gate_ctrl(dev, 1);
+ /* If we've never sent the standard in tuner core, do so now.
+ We don't do this at device probe because we don't want to
+ incur the cost of a firmware load */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->std);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ i2c_gate_ctrl(dev, 0);
+}
+
static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
@@ -1098,6 +1125,11 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
if (rc < 0)
return rc;
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
+
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(dev, AU0828_RESOURCE_VIDEO))
return -EBUSY;
@@ -1128,23 +1160,32 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
{
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
- int rc;
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int res;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ if (check_dev(dev) < 0)
+ return POLLERR;
+
+ res = v4l2_ctrl_poll(filp, wait);
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VIDEO))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VBI))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
+ return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
}
+ return POLLERR;
}
static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -1172,9 +1213,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
int width = format->fmt.pix.width;
int height = format->fmt.pix.height;
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
/* If they are demanding a format other than the one we support,
bail out (tvtime asks for UYVY and then retries with YUYV) */
if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
@@ -1193,6 +1231,7 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
format->fmt.pix.sizeimage = width * height * 2;
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ format->fmt.pix.priv = 0;
if (cmd == VIDIOC_TRY_FMT)
return 0;
@@ -1226,35 +1265,28 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct au0828_fh *fh = priv;
+ struct video_device *vdev = video_devdata(file);
+ struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
strlcpy(cap->card, dev->board.name, sizeof(cap->card));
- strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+ usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
- /*set the device capabilities */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO |
+ /* set the device capabilities */
+ cap->device_caps = V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
return 0;
}
@@ -1286,6 +1318,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = dev->frame_size;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1320,27 +1353,37 @@ 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 au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+ dev->std = norm;
+
+ au0828_init_tuner(dev);
+
+ i2c_gate_ctrl(dev, 1);
/* FIXME: when we support something other than NTSC, we are going to
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
- dev->std_set_in_tuner_core = 1;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm);
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ *norm = dev->std;
+ return 0;
+}
+
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
@@ -1368,10 +1411,13 @@ static int vidioc_enum_input(struct file *file, void *priv,
input->index = tmp;
strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
- (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) {
input->type |= V4L2_INPUT_TYPE_TUNER;
- else
+ input->audioset = 1;
+ } else {
input->type |= V4L2_INPUT_TYPE_CAMERA;
+ input->audioset = 2;
+ }
input->std = dev->vdev->tvnorms;
@@ -1386,32 +1432,25 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+static void au0828_s_input(struct au0828_dev *dev, int index)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
int i;
- dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
- index);
- if (index >= AU0828_MAX_INPUT)
- return -EINVAL;
- if (AUVI_INPUT(index).type == 0)
- return -EINVAL;
- dev->ctrl_input = index;
-
switch (AUVI_INPUT(index).type) {
case AU0828_VMUX_SVIDEO:
dev->input_type = AU0828_VMUX_SVIDEO;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_COMPOSITE:
dev->input_type = AU0828_VMUX_COMPOSITE;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_TELEVISION:
dev->input_type = AU0828_VMUX_TELEVISION;
+ dev->ctrl_ainput = 0;
break;
default:
- dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+ dprintk(1, "unknown input type set [%d]\n",
AUVI_INPUT(index).type);
break;
}
@@ -1442,55 +1481,60 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
AUVI_INPUT(index).amux, 0, 0);
- return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- unsigned int index = a->index;
+ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+ index);
+ if (index >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(index).type == 0)
+ return -EINVAL;
+ dev->ctrl_input = index;
+ au0828_s_input(dev, index);
+ return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
+{
if (a->index > 1)
return -EINVAL;
- index = dev->ctrl_ainput;
- if (index == 0)
+ if (a->index == 0)
strcpy(a->name, "Television");
else
strcpy(a->name, "Line in");
a->capability = V4L2_AUDCAP_STEREO;
- a->index = index;
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (a->index != dev->ctrl_ainput)
- return -EINVAL;
- return 0;
-}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ a->index = dev->ctrl_ainput;
+ if (a->index == 0)
+ strcpy(a->name, "Television");
+ else
+ strcpy(a->name, "Line in");
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ a->capability = V4L2_AUDCAP_STEREO;
return 0;
-
}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+
+ if (a->index != dev->ctrl_ainput)
+ return -EINVAL;
return 0;
}
@@ -1503,12 +1547,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return -EINVAL;
strcpy(t->name, "Auvitek tuner");
+
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ i2c_gate_ctrl(dev, 0);
return 0;
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
@@ -1516,15 +1564,10 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- t->type = V4L2_TUNER_ANALOG_TV;
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
t->afc);
@@ -1539,40 +1582,31 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- freq->type = V4L2_TUNER_ANALOG_TV;
+ if (freq->tuner != 0)
+ return -EINVAL;
freq->frequency = dev->ctrl_freq;
return 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
+ struct v4l2_frequency new_freq = *freq;
if (freq->tuner != 0)
return -EINVAL;
- if (freq->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- dev->ctrl_freq = freq->frequency;
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
- if (dev->std_set_in_tuner_core == 0) {
- /* If we've never sent the standard in tuner core, do so now. We
- don't do this at device probe because we don't want to incur
- the cost of a firmware load */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
- dev->vdev->tvnorms);
- dev->std_set_in_tuner_core = 1;
- }
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+ /* Get the actual set (and possibly clamped) frequency */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ dev->ctrl_freq = new_freq.frequency;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
au0828_analog_stream_reset(dev);
@@ -1598,26 +1632,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
format->fmt.vbi.count[1] = dev->vbi_height;
format->fmt.vbi.start[0] = 21;
format->fmt.vbi.start[1] = 284;
-
- return 0;
-}
-
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
-
- if (v4l2_chip_match_host(&chip->match)) {
- chip->ident = V4L2_IDENT_AU0828;
- return 0;
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
- if (chip->ident == V4L2_IDENT_NONE)
- return -EINVAL;
+ memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
return 0;
}
@@ -1664,6 +1679,7 @@ static int vidioc_streamon(struct file *file, void *priv,
if (unlikely(!res_get(fh, get_ressource(fh))))
return -EBUSY;
+ au0828_init_tuner(dev);
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
au0828_analog_stream_enable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
@@ -1742,37 +1758,30 @@ static int vidioc_g_register(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
reg->val = au0828_read(dev, reg->reg);
+ reg->size = 1;
return 0;
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
return au0828_writereg(dev, reg->reg, reg->val);
}
#endif
+static int vidioc_log_status(struct file *file, void *fh)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ v4l2_ctrl_log_status(file, fh);
+ v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status);
+ return 0;
+}
+
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
@@ -1872,7 +1881,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
@@ -1881,12 +1892,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -1897,7 +1906,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct video_device au0828_video_template = {
@@ -1905,7 +1916,6 @@ static const struct video_device au0828_video_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M,
};
/**************************************************************************/
@@ -1972,7 +1982,12 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->field_size = dev->width * dev->height;
dev->frame_size = dev->field_size << 1;
dev->bytesperline = dev->width << 1;
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
dev->ctrl_ainput = 0;
+ dev->ctrl_freq = 960;
+ dev->std = V4L2_STD_NTSC_M;
+ au0828_s_input(dev, 0);
/* allocate and fill v4l2 video struct */
dev->vdev = video_device_alloc();
@@ -1991,14 +2006,16 @@ int au0828_analog_register(struct au0828_dev *dev,
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
- dev->vdev->parent = &dev->usbdev->dev;
+ dev->vdev->v4l2_dev = &dev->v4l2_dev;
dev->vdev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags);
strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
- dev->vbi_dev->parent = &dev->usbdev->dev;
+ dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
dev->vbi_dev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags);
strcpy(dev->vbi_dev->name, "au0828a vbi");
/* Register the v4l2 device */
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 66a56ef7bbe..7112b9d956f 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -28,6 +28,8 @@
#include <linux/videodev2.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
/* DVB */
#include "demux.h"
@@ -100,6 +102,10 @@ struct au0828_dvb {
struct dmx_frontend fe_mem;
struct dvb_net net;
int feeding;
+ int start_count;
+ int stop_count;
+
+ int (*set_frontend)(struct dvb_frontend *fe);
};
enum au0828_stream_state {
@@ -118,6 +124,9 @@ enum au0828_dev_state {
};
struct au0828_fh {
+ /* must be the first field of this struct! */
+ struct v4l2_fh fh;
+
struct au0828_dev *dev;
unsigned int resources;
@@ -199,8 +208,11 @@ struct au0828_dev {
struct au0828_dvb dvb;
struct work_struct restart_streaming;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog */
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
+#endif
int users;
unsigned int resources; /* resources in use */
struct video_device *vdev;
@@ -214,6 +226,7 @@ struct au0828_dev {
int vbi_width;
int vbi_height;
u32 vbi_read;
+ v4l2_std_id std;
u32 field_size;
u32 frame_size;
u32 bytesperline;
@@ -251,6 +264,10 @@ struct au0828_dev {
/* USB / URB Related */
int urb_streaming;
struct urb *urbs[URB_COUNT];
+
+ /* Preallocated transfer digital transfer buffers */
+
+ char *dig_transfer_buffer[URB_COUNT];
};
/* ----------------------------------------------------------- */