forked from Minki/linux
V4L/DVB (11066): au0828: add support for analog functionality in bridge
Add support for the analog functionality found in the au0828 bridge Thanks to Michael Krufky <mkrufky@linuxtv.org> and Steven Toth <stoth@linuxtv.org> for providing sample hardware, engineering level support, and testing. Signed-off-by: Devin Heitmueller <dheitmueller@linuxtv.org> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> [mchehab@redhat.com: fix compilation by adding linux/version.h] Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
968cf78285
commit
8b2f079523
@ -1,4 +1,4 @@
|
||||
au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
|
||||
au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
|
||||
|
||||
|
@ -21,6 +21,18 @@
|
||||
|
||||
#include "au0828.h"
|
||||
#include "au0828-cards.h"
|
||||
#include "au8522.h"
|
||||
|
||||
void hvr950q_cs5340_audio(void *priv, int enable)
|
||||
{
|
||||
/* Because the HVR-950q shares an i2s bus between the cs5340 and the
|
||||
au8522, we need to hold cs5340 in reset when using the au8522 */
|
||||
struct au0828_dev *dev = priv;
|
||||
if (enable == 1)
|
||||
au0828_set(dev, REG_000, 0x10);
|
||||
else
|
||||
au0828_clear(dev, REG_000, 0x10);
|
||||
}
|
||||
|
||||
struct au0828_board au0828_boards[] = {
|
||||
[AU0828_BOARD_UNKNOWN] = {
|
||||
@ -31,6 +43,25 @@ struct au0828_board au0828_boards[] = {
|
||||
},
|
||||
[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
|
||||
.name = "Hauppauge HVR950Q",
|
||||
.input = {
|
||||
{
|
||||
.type = AU0828_VMUX_TELEVISION,
|
||||
.vmux = AU8522_COMPOSITE_CH4_SIF,
|
||||
.amux = AU8522_AUDIO_SIF,
|
||||
},
|
||||
{
|
||||
.type = AU0828_VMUX_COMPOSITE,
|
||||
.vmux = AU8522_COMPOSITE_CH1,
|
||||
.amux = AU8522_AUDIO_NONE,
|
||||
.audio_setup = hvr950q_cs5340_audio,
|
||||
},
|
||||
{
|
||||
.type = AU0828_VMUX_SVIDEO,
|
||||
.vmux = AU8522_SVIDEO_CH13,
|
||||
.amux = AU8522_AUDIO_NONE,
|
||||
.audio_setup = hvr950q_cs5340_audio,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
|
||||
.name = "Hauppauge HVR950Q rev xxF8",
|
||||
@ -144,21 +175,23 @@ void au0828_gpio_setup(struct au0828_dev *dev)
|
||||
* 4 - CS5340
|
||||
* 5 - AU8522 Demodulator
|
||||
* 6 - eeprom W/P
|
||||
* 7 - power supply
|
||||
* 9 - XC5000 Tuner
|
||||
*/
|
||||
|
||||
/* Into reset */
|
||||
au0828_write(dev, REG_003, 0x02);
|
||||
au0828_write(dev, REG_002, 0x88 | 0x20);
|
||||
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
|
||||
au0828_write(dev, REG_001, 0x0);
|
||||
au0828_write(dev, REG_000, 0x0);
|
||||
msleep(100);
|
||||
|
||||
/* Out of reset */
|
||||
/* 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, 0x88 | 0x20);
|
||||
au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
|
||||
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
|
||||
au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
|
||||
|
||||
msleep(250);
|
||||
break;
|
||||
case AU0828_BOARD_DVICO_FUSIONHDTV7:
|
||||
|
@ -146,6 +146,8 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
|
||||
/* Digital TV */
|
||||
au0828_dvb_unregister(dev);
|
||||
|
||||
au0828_analog_unregister(dev);
|
||||
|
||||
/* I2C */
|
||||
au0828_i2c_unregister(dev);
|
||||
|
||||
@ -162,9 +164,11 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
|
||||
static int au0828_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int ifnum;
|
||||
int ifnum, i;
|
||||
struct au0828_dev *dev;
|
||||
struct usb_device *usbdev = interface_to_usbdev(interface);
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
|
||||
ifnum = interface->altsetting->desc.bInterfaceNumber;
|
||||
|
||||
@ -189,6 +193,30 @@ static int au0828_usb_probe(struct usb_interface *interface,
|
||||
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
/* set au0828 usb interface0 to as5 */
|
||||
usb_set_interface(usbdev,
|
||||
interface->cur_altsetting->desc.bInterfaceNumber, 5);
|
||||
|
||||
/* Figure out which endpoint has the isoc interface */
|
||||
iface_desc = interface->cur_altsetting;
|
||||
for(i = 0; i < iface_desc->desc.bNumEndpoints; i++){
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
if(((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
|
||||
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)){
|
||||
|
||||
/* we find our isoc in endpoint */
|
||||
u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
dev->max_pkt_size = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
|
||||
dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
|
||||
}
|
||||
}
|
||||
if(!(dev->isoc_in_endpointaddr)) {
|
||||
printk("Could not locate isoc endpoint\n");
|
||||
kfree(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
/* Power Up the bridge */
|
||||
au0828_write(dev, REG_600, 1 << 4);
|
||||
|
||||
@ -201,6 +229,9 @@ static int au0828_usb_probe(struct usb_interface *interface,
|
||||
/* Setup */
|
||||
au0828_card_setup(dev);
|
||||
|
||||
/* Analog TV */
|
||||
au0828_analog_register(dev);
|
||||
|
||||
/* Digital TV */
|
||||
au0828_dvb_register(dev);
|
||||
|
||||
|
@ -27,6 +27,9 @@
|
||||
#define REG_002 0x002
|
||||
#define REG_003 0x003
|
||||
|
||||
#define AU0828_SENSORCTRL_100 0x100
|
||||
#define AU0828_SENSORCTRL_VBI_103 0x103
|
||||
|
||||
#define REG_200 0x200
|
||||
#define REG_201 0x201
|
||||
#define REG_202 0x202
|
||||
@ -35,4 +38,7 @@
|
||||
#define REG_209 0x209
|
||||
#define REG_2FF 0x2ff
|
||||
|
||||
/* Audio registers */
|
||||
#define AU0828_AUDIOCTRL_50C 0x50C
|
||||
|
||||
#define REG_600 0x600
|
||||
|
1677
drivers/media/video/au0828/au0828-video.c
Normal file
1677
drivers/media/video/au0828/au0828-video.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,10 @@
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <media/tveeprom.h>
|
||||
|
||||
/* Analog */
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/videobuf-vmalloc.h>
|
||||
|
||||
/* DVB */
|
||||
#include "demux.h"
|
||||
#include "dmxdev.h"
|
||||
@ -39,8 +43,48 @@
|
||||
#define URB_COUNT 16
|
||||
#define URB_BUFSIZE (0xe522)
|
||||
|
||||
/* Analog constants */
|
||||
#define NTSC_STD_W 720
|
||||
#define NTSC_STD_H 480
|
||||
|
||||
#define AU0828_INTERLACED_DEFAULT 1
|
||||
#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
|
||||
|
||||
/* Defination for AU0828 USB transfer */
|
||||
#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
|
||||
#define AU0828_ISO_PACKETS_PER_URB 10
|
||||
#define AU0828_ISO_MAX_FRAME_SIZE (3 * 1024)
|
||||
#define AU0828_ISO_BUFFER_SIZE (AU0828_ISO_PACKETS_PER_URB * AU0828_ISO_MAX_FRAME_SIZE)
|
||||
|
||||
#define AU0828_MIN_BUF 4
|
||||
#define AU0828_DEF_BUF 8
|
||||
|
||||
#define AU0828_MAX_IMAGES 10
|
||||
#define AU0828_FRAME_SIZE (1028 * 1024 * 4)
|
||||
#define AU0828_URB_TIMEOUT msecs_to_jiffies(AU0828_MAX_ISO_BUFS * AU0828_ISO_PACKETS_PER_URB)
|
||||
|
||||
#define AU0828_MAX_INPUT 4
|
||||
|
||||
enum au0828_itype {
|
||||
AU0828_VMUX_COMPOSITE = 1,
|
||||
AU0828_VMUX_SVIDEO,
|
||||
AU0828_VMUX_CABLE,
|
||||
AU0828_VMUX_TELEVISION,
|
||||
AU0828_VMUX_DVB,
|
||||
AU0828_VMUX_DEBUG
|
||||
};
|
||||
|
||||
struct au0828_input {
|
||||
enum au0828_itype type;
|
||||
unsigned int vmux;
|
||||
unsigned int amux;
|
||||
void (*audio_setup) (void *priv, int enable);
|
||||
};
|
||||
|
||||
struct au0828_board {
|
||||
char *name;
|
||||
struct au0828_input input[AU0828_MAX_INPUT];
|
||||
|
||||
};
|
||||
|
||||
struct au0828_dvb {
|
||||
@ -55,6 +99,83 @@ struct au0828_dvb {
|
||||
int feeding;
|
||||
};
|
||||
|
||||
enum au0828_stream_state {
|
||||
STREAM_OFF,
|
||||
STREAM_INTERRUPT,
|
||||
STREAM_ON
|
||||
};
|
||||
|
||||
#define AUVI_INPUT(nr) (&au0828_boards[dev->board].input[nr])
|
||||
|
||||
/* device state */
|
||||
enum au0828_dev_state {
|
||||
DEV_INITIALIZED = 0x01,
|
||||
DEV_DISCONNECTED = 0x02,
|
||||
DEV_MISCONFIGURED = 0x04
|
||||
};
|
||||
|
||||
struct au0828_fh {
|
||||
struct au0828_dev *dev;
|
||||
unsigned int stream_on:1; /* Locks streams */
|
||||
struct videobuf_queue vb_vidq;
|
||||
enum v4l2_buf_type type;
|
||||
};
|
||||
|
||||
struct au0828_usb_isoc_ctl {
|
||||
/* max packet size of isoc transaction */
|
||||
int max_pkt_size;
|
||||
|
||||
/* number of allocated urbs */
|
||||
int num_bufs;
|
||||
|
||||
/* urb for isoc transfers */
|
||||
struct urb **urb;
|
||||
|
||||
/* transfer buffers for isoc transfer */
|
||||
char **transfer_buffer;
|
||||
|
||||
/* Last buffer command and region */
|
||||
u8 cmd;
|
||||
int pos, size, pktsize;
|
||||
|
||||
/* Last field: ODD or EVEN? */
|
||||
int field;
|
||||
|
||||
/* Stores incomplete commands */
|
||||
u32 tmp_buf;
|
||||
int tmp_buf_len;
|
||||
|
||||
/* Stores already requested buffers */
|
||||
struct au0828_buffer *buf;
|
||||
|
||||
/* Stores the number of received fields */
|
||||
int nfields;
|
||||
|
||||
/* isoc urb callback */
|
||||
int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
|
||||
|
||||
};
|
||||
|
||||
/* buffer for one video frame */
|
||||
struct au0828_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
|
||||
struct list_head frame;
|
||||
int top_field;
|
||||
int receiving;
|
||||
};
|
||||
|
||||
struct au0828_dmaqueue {
|
||||
struct list_head active;
|
||||
struct list_head queued;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
|
||||
/* Counters to control buffer fill */
|
||||
int pos;
|
||||
};
|
||||
|
||||
struct au0828_dev {
|
||||
struct mutex mutex;
|
||||
struct usb_device *usbdev;
|
||||
@ -70,16 +191,49 @@ struct au0828_dev {
|
||||
/* Digital */
|
||||
struct au0828_dvb dvb;
|
||||
|
||||
/* Analog */
|
||||
struct list_head au0828list;
|
||||
int users;
|
||||
unsigned int stream_on:1; /* Locks streams */
|
||||
struct video_device *vdev;
|
||||
struct video_device *vbi_dev;
|
||||
int width;
|
||||
int height;
|
||||
u32 field_size;
|
||||
u32 frame_size;
|
||||
u32 bytesperline;
|
||||
int type;
|
||||
u8 ctrl_ainput;
|
||||
__u8 isoc_in_endpointaddr;
|
||||
u8 isoc_init_ok;
|
||||
int greenscreen_detected;
|
||||
unsigned int frame_count;
|
||||
int ctrl_freq;
|
||||
int input_type;
|
||||
unsigned int ctrl_input;
|
||||
enum au0828_dev_state dev_state;
|
||||
enum au0828_stream_state stream_state;
|
||||
wait_queue_head_t open;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
/* Isoc control struct */
|
||||
struct au0828_dmaqueue vidq;
|
||||
struct au0828_usb_isoc_ctl isoc_ctl;
|
||||
spinlock_t slock;
|
||||
|
||||
/* usb transfer */
|
||||
int alt; /* alternate */
|
||||
int max_pkt_size; /* max packet size of isoc transaction */
|
||||
int num_alt; /* Number of alternative settings */
|
||||
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
|
||||
struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
|
||||
char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
|
||||
transfer */
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
@ -114,6 +268,12 @@ extern int au0828_i2c_unregister(struct au0828_dev *dev);
|
||||
extern void au0828_call_i2c_clients(struct au0828_dev *dev,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* au0828-video.c */
|
||||
int au0828_analog_register(struct au0828_dev *dev);
|
||||
int au0828_analog_stream_disable(struct au0828_dev *d);
|
||||
void au0828_analog_unregister(struct au0828_dev *dev);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* au0828-dvb.c */
|
||||
extern int au0828_dvb_register(struct au0828_dev *dev);
|
||||
|
Loading…
Reference in New Issue
Block a user