V4L/DVB (11070): au0828: Rework the way the analog video binding occurs
Rework the way boards are managed so that we can change the board description based on the Hauppauge eeprom (modeled after cx88-cards.c). Also, make sure that we don't load the analog stack if there are no analog inputs defined in the board profile. Thanks to Michael Krufky <mkrufky@linuxtv.org> for providing information on the various ways different Hauppauge boards can be configured. Signed-off-by: Devin Heitmueller <dheitmueller@linuxtv.org> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
4ff5ed44f8
commit
f1add5b5ec
|
@ -22,6 +22,8 @@
|
||||||
#include "au0828.h"
|
#include "au0828.h"
|
||||||
#include "au0828-cards.h"
|
#include "au0828-cards.h"
|
||||||
#include "au8522.h"
|
#include "au8522.h"
|
||||||
|
#include "media/tuner.h"
|
||||||
|
#include "media/v4l2-common.h"
|
||||||
|
|
||||||
void hvr950q_cs5340_audio(void *priv, int enable)
|
void hvr950q_cs5340_audio(void *priv, int enable)
|
||||||
{
|
{
|
||||||
|
@ -37,9 +39,13 @@ void hvr950q_cs5340_audio(void *priv, int enable)
|
||||||
struct au0828_board au0828_boards[] = {
|
struct au0828_board au0828_boards[] = {
|
||||||
[AU0828_BOARD_UNKNOWN] = {
|
[AU0828_BOARD_UNKNOWN] = {
|
||||||
.name = "Unknown board",
|
.name = "Unknown board",
|
||||||
|
.tuner_type = UNSET,
|
||||||
|
.tuner_addr = ADDR_UNSET,
|
||||||
},
|
},
|
||||||
[AU0828_BOARD_HAUPPAUGE_HVR850] = {
|
[AU0828_BOARD_HAUPPAUGE_HVR850] = {
|
||||||
.name = "Hauppauge HVR850",
|
.name = "Hauppauge HVR850",
|
||||||
|
.tuner_type = TUNER_XC5000,
|
||||||
|
.tuner_addr = 0x61,
|
||||||
.input = {
|
.input = {
|
||||||
{
|
{
|
||||||
.type = AU0828_VMUX_TELEVISION,
|
.type = AU0828_VMUX_TELEVISION,
|
||||||
|
@ -62,6 +68,8 @@ struct au0828_board au0828_boards[] = {
|
||||||
},
|
},
|
||||||
[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
|
[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
|
||||||
.name = "Hauppauge HVR950Q",
|
.name = "Hauppauge HVR950Q",
|
||||||
|
.tuner_type = TUNER_XC5000,
|
||||||
|
.tuner_addr = 0x61,
|
||||||
.input = {
|
.input = {
|
||||||
{
|
{
|
||||||
.type = AU0828_VMUX_TELEVISION,
|
.type = AU0828_VMUX_TELEVISION,
|
||||||
|
@ -84,12 +92,18 @@ struct au0828_board au0828_boards[] = {
|
||||||
},
|
},
|
||||||
[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
|
[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
|
||||||
.name = "Hauppauge HVR950Q rev xxF8",
|
.name = "Hauppauge HVR950Q rev xxF8",
|
||||||
|
.tuner_type = UNSET,
|
||||||
|
.tuner_addr = ADDR_UNSET,
|
||||||
},
|
},
|
||||||
[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
|
[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
|
||||||
.name = "DViCO FusionHDTV USB",
|
.name = "DViCO FusionHDTV USB",
|
||||||
|
.tuner_type = UNSET,
|
||||||
|
.tuner_addr = ADDR_UNSET,
|
||||||
},
|
},
|
||||||
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
|
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
|
||||||
.name = "Hauppauge Woodbury",
|
.name = "Hauppauge Woodbury",
|
||||||
|
.tuner_type = UNSET,
|
||||||
|
.tuner_addr = ADDR_UNSET,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +116,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
|
||||||
|
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
switch (dev->board) {
|
switch (dev->boardnr) {
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
||||||
|
@ -131,6 +145,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
|
||||||
struct tveeprom tv;
|
struct tveeprom tv;
|
||||||
|
|
||||||
tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
|
tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
|
||||||
|
dev->board.tuner_type = tv.tuner_type;
|
||||||
|
|
||||||
/* Make sure we support the board model */
|
/* Make sure we support the board model */
|
||||||
switch (tv.model) {
|
switch (tv.model) {
|
||||||
|
@ -157,15 +172,20 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
|
||||||
void au0828_card_setup(struct au0828_dev *dev)
|
void au0828_card_setup(struct au0828_dev *dev)
|
||||||
{
|
{
|
||||||
static u8 eeprom[256];
|
static u8 eeprom[256];
|
||||||
|
struct tuner_setup tun_setup;
|
||||||
|
unsigned int mode_mask = T_ANALOG_TV |
|
||||||
|
T_DIGITAL_TV;
|
||||||
|
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
|
||||||
|
|
||||||
if (dev->i2c_rc == 0) {
|
if (dev->i2c_rc == 0) {
|
||||||
dev->i2c_client.addr = 0xa0 >> 1;
|
dev->i2c_client.addr = 0xa0 >> 1;
|
||||||
tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
|
tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dev->board) {
|
switch (dev->boardnr) {
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
||||||
|
@ -174,6 +194,25 @@ void au0828_card_setup(struct au0828_dev *dev)
|
||||||
hauppauge_eeprom(dev, eeprom+0xa0);
|
hauppauge_eeprom(dev, eeprom+0xa0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->board.input != NULL) {
|
||||||
|
/* Load the analog demodulator driver (note this would need to
|
||||||
|
be abstracted out if we ever need to support a different
|
||||||
|
demod) */
|
||||||
|
request_module("au8522");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup tuners */
|
||||||
|
if (dev->board.tuner_type != TUNER_ABSENT) {
|
||||||
|
/* Load the tuner module, which does the attach */
|
||||||
|
request_module("tuner");
|
||||||
|
|
||||||
|
tun_setup.mode_mask = mode_mask;
|
||||||
|
tun_setup.type = dev->board.tuner_type;
|
||||||
|
tun_setup.addr = dev->board.tuner_addr;
|
||||||
|
tun_setup.tuner_callback = au0828_tuner_callback;
|
||||||
|
au0828_call_i2c_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -185,7 +224,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
|
||||||
{
|
{
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
switch (dev->board) {
|
switch (dev->boardnr) {
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
|
||||||
|
|
|
@ -146,7 +146,8 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
|
||||||
/* Digital TV */
|
/* Digital TV */
|
||||||
au0828_dvb_unregister(dev);
|
au0828_dvb_unregister(dev);
|
||||||
|
|
||||||
au0828_analog_unregister(dev);
|
if (dev->board.input != NULL)
|
||||||
|
au0828_analog_unregister(dev);
|
||||||
|
|
||||||
/* I2C */
|
/* I2C */
|
||||||
au0828_i2c_unregister(dev);
|
au0828_i2c_unregister(dev);
|
||||||
|
@ -189,7 +190,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
|
||||||
mutex_init(&dev->mutex);
|
mutex_init(&dev->mutex);
|
||||||
mutex_init(&dev->dvb.lock);
|
mutex_init(&dev->dvb.lock);
|
||||||
dev->usbdev = usbdev;
|
dev->usbdev = usbdev;
|
||||||
dev->board = id->driver_info;
|
dev->boardnr = id->driver_info;
|
||||||
|
|
||||||
usb_set_intfdata(interface, dev);
|
usb_set_intfdata(interface, dev);
|
||||||
|
|
||||||
|
@ -230,14 +231,14 @@ static int au0828_usb_probe(struct usb_interface *interface,
|
||||||
au0828_card_setup(dev);
|
au0828_card_setup(dev);
|
||||||
|
|
||||||
/* Analog TV */
|
/* Analog TV */
|
||||||
au0828_analog_register(dev);
|
if (dev->board.input != NULL)
|
||||||
|
au0828_analog_register(dev);
|
||||||
|
|
||||||
/* Digital TV */
|
/* Digital TV */
|
||||||
au0828_dvb_register(dev);
|
au0828_dvb_register(dev);
|
||||||
|
|
||||||
printk(KERN_INFO "Registered device AU0828 [%s]\n",
|
printk(KERN_INFO "Registered device AU0828 [%s]\n",
|
||||||
au0828_boards[dev->board].name == NULL ? "Unset" :
|
dev->board.name == NULL ? "Unset" : dev->board.name);
|
||||||
au0828_boards[dev->board].name);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,7 +378,7 @@ int au0828_dvb_register(struct au0828_dev *dev)
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
/* init frontend */
|
/* init frontend */
|
||||||
switch (dev->board) {
|
switch (dev->boardnr) {
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
||||||
dvb->frontend = dvb_attach(au8522_attach,
|
dvb->frontend = dvb_attach(au8522_attach,
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ static int vidioc_querycap(struct file *file, void *priv,
|
||||||
|
|
||||||
memset(cap, 0, sizeof(*cap));
|
memset(cap, 0, sizeof(*cap));
|
||||||
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
|
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
|
||||||
strlcpy(cap->card, au0828_boards[dev->board].name, sizeof(cap->card));
|
strlcpy(cap->card, dev->board.name, sizeof(cap->card));
|
||||||
strlcpy(cap->bus_info, dev->usbdev->dev.bus_id, sizeof(cap->bus_info));
|
strlcpy(cap->bus_info, dev->usbdev->dev.bus_id, sizeof(cap->bus_info));
|
||||||
|
|
||||||
cap->version = AU0828_VERSION_CODE;
|
cap->version = AU0828_VERSION_CODE;
|
||||||
|
@ -1127,14 +1127,14 @@ static int vidioc_enum_input(struct file *file, void *priv,
|
||||||
|
|
||||||
if(tmp > AU0828_MAX_INPUT)
|
if(tmp > AU0828_MAX_INPUT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if(AUVI_INPUT(tmp)->type == 0)
|
if(AUVI_INPUT(tmp).type == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
memset(input, 0, sizeof(*input));
|
memset(input, 0, sizeof(*input));
|
||||||
input->index = tmp;
|
input->index = tmp;
|
||||||
strcpy(input->name, inames[AUVI_INPUT(tmp)->type]);
|
strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
|
||||||
if((AUVI_INPUT(tmp)->type == AU0828_VMUX_TELEVISION) ||
|
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;
|
input->type |= V4L2_INPUT_TYPE_TUNER;
|
||||||
else
|
else
|
||||||
input->type |= V4L2_INPUT_TYPE_CAMERA;
|
input->type |= V4L2_INPUT_TYPE_CAMERA;
|
||||||
|
@ -1163,11 +1163,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
|
||||||
index);
|
index);
|
||||||
if(index >= AU0828_MAX_INPUT)
|
if(index >= AU0828_MAX_INPUT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if(AUVI_INPUT(index)->type == 0)
|
if(AUVI_INPUT(index).type == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
dev->ctrl_input = index;
|
dev->ctrl_input = index;
|
||||||
|
|
||||||
switch(AUVI_INPUT(index)->type) {
|
switch(AUVI_INPUT(index).type) {
|
||||||
case AU0828_VMUX_SVIDEO:
|
case AU0828_VMUX_SVIDEO:
|
||||||
{
|
{
|
||||||
dev->input_type = AU0828_VMUX_SVIDEO;
|
dev->input_type = AU0828_VMUX_SVIDEO;
|
||||||
|
@ -1187,13 +1187,13 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
route.input = AUVI_INPUT(index)->vmux;
|
route.input = AUVI_INPUT(index).vmux;
|
||||||
route.output = 0;
|
route.output = 0;
|
||||||
au0828_call_i2c_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
|
au0828_call_i2c_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
|
||||||
|
|
||||||
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
||||||
int enable = 0;
|
int enable = 0;
|
||||||
if (AUVI_INPUT(i)->audio_setup == NULL) {
|
if (AUVI_INPUT(i).audio_setup == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,18 +1202,18 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
|
||||||
else
|
else
|
||||||
enable = 0;
|
enable = 0;
|
||||||
if (enable) {
|
if (enable) {
|
||||||
(AUVI_INPUT(i)->audio_setup)(dev, enable);
|
(AUVI_INPUT(i).audio_setup)(dev, enable);
|
||||||
} else {
|
} else {
|
||||||
/* Make sure we leave it turned on if some
|
/* Make sure we leave it turned on if some
|
||||||
other input is routed to this callback */
|
other input is routed to this callback */
|
||||||
if ((AUVI_INPUT(i)->audio_setup) !=
|
if ((AUVI_INPUT(i).audio_setup) !=
|
||||||
((AUVI_INPUT(index)->audio_setup))) {
|
((AUVI_INPUT(index).audio_setup))) {
|
||||||
(AUVI_INPUT(i)->audio_setup)(dev, enable);
|
(AUVI_INPUT(i).audio_setup)(dev, enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
route.input = AUVI_INPUT(index)->amux;
|
route.input = AUVI_INPUT(index).amux;
|
||||||
au0828_call_i2c_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
|
au0828_call_i2c_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
|
||||||
&route);
|
&route);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1419,10 +1419,10 @@ static int vidioc_streamoff(struct file *file, void *priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
||||||
if (AUVI_INPUT(i)->audio_setup == NULL) {
|
if (AUVI_INPUT(i).audio_setup == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(AUVI_INPUT(i)->audio_setup)(dev, 0);
|
(AUVI_INPUT(i).audio_setup)(dev, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev->lock);
|
mutex_lock(&dev->lock);
|
||||||
|
@ -1603,14 +1603,6 @@ int au0828_analog_register(struct au0828_dev *dev)
|
||||||
|
|
||||||
dprintk(1, "au0828_analog_register called!\n");
|
dprintk(1, "au0828_analog_register called!\n");
|
||||||
|
|
||||||
/* Load the analog demodulator driver (note this would need to be
|
|
||||||
abstracted out if we ever need to support a different demod) */
|
|
||||||
request_module("au8522");
|
|
||||||
|
|
||||||
/* Load the tuner module, which results in i2c enumeration and
|
|
||||||
attachment of whatever tuner is on the bus */
|
|
||||||
request_module("tuner");
|
|
||||||
|
|
||||||
init_waitqueue_head(&dev->open);
|
init_waitqueue_head(&dev->open);
|
||||||
spin_lock_init(&dev->slock);
|
spin_lock_init(&dev->slock);
|
||||||
mutex_init(&dev->lock);
|
mutex_init(&dev->lock);
|
||||||
|
|
|
@ -83,6 +83,8 @@ struct au0828_input {
|
||||||
|
|
||||||
struct au0828_board {
|
struct au0828_board {
|
||||||
char *name;
|
char *name;
|
||||||
|
unsigned int tuner_type;
|
||||||
|
unsigned char tuner_addr;
|
||||||
struct au0828_input input[AU0828_MAX_INPUT];
|
struct au0828_input input[AU0828_MAX_INPUT];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -105,7 +107,7 @@ enum au0828_stream_state {
|
||||||
STREAM_ON
|
STREAM_ON
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AUVI_INPUT(nr) (&au0828_boards[dev->board].input[nr])
|
#define AUVI_INPUT(nr) (dev->board.input[nr])
|
||||||
|
|
||||||
/* device state */
|
/* device state */
|
||||||
enum au0828_dev_state {
|
enum au0828_dev_state {
|
||||||
|
@ -179,7 +181,8 @@ struct au0828_dmaqueue {
|
||||||
struct au0828_dev {
|
struct au0828_dev {
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
struct usb_device *usbdev;
|
struct usb_device *usbdev;
|
||||||
int board;
|
int boardnr;
|
||||||
|
struct au0828_board board;
|
||||||
u8 ctrlmsg[64];
|
u8 ctrlmsg[64];
|
||||||
|
|
||||||
/* I2C */
|
/* I2C */
|
||||||
|
|
Loading…
Reference in New Issue