Commit eac94356 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab Committed by Linus Torvalds

[PATCH] V4L: 907: em28xx cleanups and fixes

- Em28xx cleanups and fixes.
- Some cleanups and audio amux adjust.
- em28xx will allways try, by default, the biggest size alt.
- Fixes audio mux code.
- Fixes some logs.
- Adds support for digital output for WinTV USB2 board.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c3d93192
...@@ -128,7 +128,7 @@ struct em28xx_board em28xx_boards[] = { ...@@ -128,7 +128,7 @@ struct em28xx_board em28xx_boards[] = {
.input = {{ .input = {{
.type = EM28XX_VMUX_TELEVISION, .type = EM28XX_VMUX_TELEVISION,
.vmux = 0, .vmux = 0,
.amux = 0, .amux = 6,
},{ },{
.type = EM28XX_VMUX_SVIDEO, .type = EM28XX_VMUX_SVIDEO,
.vmux = 2, .vmux = 2,
...@@ -261,9 +261,11 @@ void em28xx_card_setup(struct em28xx *dev) ...@@ -261,9 +261,11 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */ /* request some modules */
if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) { if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
struct tveeprom tv; struct tveeprom tv;
struct v4l2_audioout ao;
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
request_module("tveeprom"); request_module("tveeprom");
request_module("ir-kbd-i2c"); request_module("ir-kbd-i2c");
request_module("msp3400");
#endif #endif
/* Call first TVeeprom */ /* Call first TVeeprom */
...@@ -273,10 +275,13 @@ void em28xx_card_setup(struct em28xx *dev) ...@@ -273,10 +275,13 @@ void em28xx_card_setup(struct em28xx *dev)
dev->tuner_type= tv.tuner_type; dev->tuner_type= tv.tuner_type;
if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
dev->has_msp34xx=1; dev->has_msp34xx=1;
} else dev->has_msp34xx=0; memset (&ao,0,sizeof(ao));
em28xx_write_regs_req(dev,0x06,0x00,"\x40",1);// Serial Bus Frequency Select Register
em28xx_write_regs_req(dev,0x0f,0x00,"\x87",1);// XCLK Frequency Select Register ao.index=2;
em28xx_write_regs_req(dev,0x88,0x0d,"\xd0",1); ao.mode=V4L2_AUDMODE_32BITS;
em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
} else
dev->has_msp34xx=0;
} }
} }
......
...@@ -797,20 +797,9 @@ int em28xx_set_alternate(struct em28xx *dev) ...@@ -797,20 +797,9 @@ int em28xx_set_alternate(struct em28xx *dev)
dev->alt = alt; dev->alt = alt;
if (dev->alt == 0) { if (dev->alt == 0) {
int i; int i;
if(dev->is_em2800){ /* always use the max packet size for em2800 based devices */
for(i=0;i< EM28XX_MAX_ALT; i++) for(i=0;i< EM28XX_MAX_ALT; i++)
if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt]) if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
dev->alt=i; dev->alt=i;
}else{
unsigned int min_pkt_size = dev->field_size / 137; /* FIXME: empiric magic number */
em28xx_coredbg("minimum isoc packet size: %u", min_pkt_size);
dev->alt = 7;
for (i = 1; i < EM28XX_MAX_ALT; i += 2) /* FIXME: skip even alternate: why do they not work? */
if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
dev->alt = i;
break;
}
}
} }
if (dev->alt != prev_alt) { if (dev->alt != prev_alt) {
......
...@@ -277,6 +277,35 @@ static void em28xx_empty_framequeues(struct em28xx *dev) ...@@ -277,6 +277,35 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
} }
} }
static void video_mux(struct em28xx *dev, int index)
{
int input, ainput;
input = INPUT(index)->vmux;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
if (dev->has_msp34xx) {
em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
ainput = EM28XX_AUDIO_SRC_TUNER;
em28xx_audio_source(dev, ainput);
} else {
switch (dev->ctl_ainput) {
case 0:
ainput = EM28XX_AUDIO_SRC_TUNER;
break;
default:
ainput = EM28XX_AUDIO_SRC_LINE;
}
em28xx_audio_source(dev, ainput);
}
}
/* /*
* em28xx_v4l2_open() * em28xx_v4l2_open()
* inits the device and starts isoc transfer * inits the device and starts isoc transfer
...@@ -298,7 +327,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) ...@@ -298,7 +327,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
filp->private_data=dev; filp->private_data=dev;
em28xx_videodbg("users=%d", dev->users); em28xx_videodbg("users=%d\n", dev->users);
if (!down_read_trylock(&em28xx_disconnect)) if (!down_read_trylock(&em28xx_disconnect))
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -352,6 +381,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) ...@@ -352,6 +381,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->state |= DEV_INITIALIZED; dev->state |= DEV_INITIALIZED;
video_mux(dev, 0);
err: err:
up(&dev->lock); up(&dev->lock);
up_read(&em28xx_disconnect); up_read(&em28xx_disconnect);
...@@ -386,7 +417,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) ...@@ -386,7 +417,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
int errCode; int errCode;
struct em28xx *dev=filp->private_data; struct em28xx *dev=filp->private_data;
em28xx_videodbg("users=%d", dev->users); em28xx_videodbg("users=%d\n", dev->users);
down(&dev->lock); down(&dev->lock);
...@@ -404,7 +435,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) ...@@ -404,7 +435,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
/* set alternate 0 */ /* set alternate 0 */
dev->alt = 0; dev->alt = 0;
em28xx_videodbg("setting alternate 0"); em28xx_videodbg("setting alternate 0\n");
errCode = usb_set_interface(dev->udev, 0, 0); errCode = usb_set_interface(dev->udev, 0, 0);
if (errCode < 0) { if (errCode < 0) {
em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
...@@ -434,20 +465,20 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, ...@@ -434,20 +465,20 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
return -ERESTARTSYS; return -ERESTARTSYS;
if (dev->state & DEV_DISCONNECTED) { if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("device not present"); em28xx_videodbg("device not present\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -ENODEV; return -ENODEV;
} }
if (dev->state & DEV_MISCONFIGURED) { if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg("device misconfigured; close and open it again"); em28xx_videodbg("device misconfigured; close and open it again\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -EIO; return -EIO;
} }
if (dev->io == IO_MMAP) { if (dev->io == IO_MMAP) {
em28xx_videodbg ("IO method is set to mmap; close and open" em28xx_videodbg ("IO method is set to mmap; close and open"
" the device again to choose the read method"); " the device again to choose the read method\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -524,9 +555,9 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) ...@@ -524,9 +555,9 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
return POLLERR; return POLLERR;
if (dev->state & DEV_DISCONNECTED) { if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("device not present"); em28xx_videodbg("device not present\n");
} else if (dev->state & DEV_MISCONFIGURED) { } else if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg("device is misconfigured; close and open it again"); em28xx_videodbg("device is misconfigured; close and open it again\n");
} else { } else {
if (dev->io == IO_NONE) { if (dev->io == IO_NONE) {
if (!em28xx_request_buffers if (!em28xx_request_buffers
...@@ -595,14 +626,14 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -595,14 +626,14 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
return -ERESTARTSYS; return -ERESTARTSYS;
if (dev->state & DEV_DISCONNECTED) { if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("mmap: device not present"); em28xx_videodbg("mmap: device not present\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -ENODEV; return -ENODEV;
} }
if (dev->state & DEV_MISCONFIGURED) { if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg ("mmap: Device is misconfigured; close and " em28xx_videodbg ("mmap: Device is misconfigured; close and "
"open it again"); "open it again\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -EIO; return -EIO;
} }
...@@ -618,7 +649,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -618,7 +649,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
break; break;
} }
if (i == dev->num_frames) { if (i == dev->num_frames) {
em28xx_videodbg("mmap: user supplied mapping address is out of range"); em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -632,7 +663,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -632,7 +663,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
page = vmalloc_to_pfn((void *)pos); page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, if (remap_pfn_range(vma, start, page, PAGE_SIZE,
vma->vm_page_prot)) { vma->vm_page_prot)) {
em28xx_videodbg("mmap: rename page map failed"); em28xx_videodbg("mmap: rename page map failed\n");
up(&dev->fileop_lock); up(&dev->fileop_lock);
return -EAGAIN; return -EAGAIN;
} }
...@@ -749,7 +780,7 @@ static int em28xx_stream_interrupt(struct em28xx *dev) ...@@ -749,7 +780,7 @@ static int em28xx_stream_interrupt(struct em28xx *dev)
else if (ret) { else if (ret) {
dev->state |= DEV_MISCONFIGURED; dev->state |= DEV_MISCONFIGURED;
em28xx_videodbg("device is misconfigured; close and " em28xx_videodbg("device is misconfigured; close and "
"open /dev/video%d again", dev->vdev->minor); "open /dev/video%d again\n", dev->vdev->minor);
return ret; return ret;
} }
...@@ -800,28 +831,6 @@ static int em28xx_set_norm(struct em28xx *dev, int width, int height) ...@@ -800,28 +831,6 @@ static int em28xx_set_norm(struct em28xx *dev, int width, int height)
return 0; return 0;
} }
static void video_mux(struct em28xx *dev, int index)
{
int input, ainput;
input = INPUT(index)->vmux;
dev->ctl_input = index;
em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
dev->ctl_ainput = INPUT(index)->amux;
switch (dev->ctl_ainput) {
case 0:
ainput = EM28XX_AUDIO_SRC_TUNER;
break;
default:
ainput = EM28XX_AUDIO_SRC_LINE;
}
em28xx_audio_source(dev, ainput);
}
/* /*
* em28xx_v4l2_do_ioctl() * em28xx_v4l2_do_ioctl()
* This function is _not_ called directly, but from * This function is _not_ called directly, but from
...@@ -1062,7 +1071,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1062,7 +1071,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
t->signal = t->signal =
(status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x", t->signal, em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
t->afc); t->afc);
return 0; return 0;
} }
...@@ -1146,7 +1155,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1146,7 +1155,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
em28xx_videodbg("VIDIOC_STREAMON: starting stream"); em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
return 0; return 0;
} }
...@@ -1160,7 +1169,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1160,7 +1169,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
return -EINVAL; return -EINVAL;
if (dev->stream == STREAM_ON) { if (dev->stream == STREAM_ON) {
em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream"); em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
if ((ret = em28xx_stream_interrupt(dev))) if ((ret = em28xx_stream_interrupt(dev)))
return ret; return ret;
} }
...@@ -1234,7 +1243,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1234,7 +1243,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
{ {
struct v4l2_format *format = arg; struct v4l2_format *format = arg;
em28xx_videodbg("VIDIOC_G_FMT: type=%s", em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
format->type == format->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE ? V4L2_BUF_TYPE_VIDEO_CAPTURE ?
"V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type == "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
...@@ -1253,7 +1262,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1253,7 +1262,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
em28xx_videodbg("VIDIOC_G_FMT: %dx%d", dev->width, em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
dev->height); dev->height);
return 0; return 0;
} }
...@@ -1274,7 +1283,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1274,7 +1283,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
/* int both_fields; */ /* int both_fields; */
em28xx_videodbg("%s: type=%s", em28xx_videodbg("%s: type=%s\n",
cmd == cmd ==
VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
"VIDIOC_S_FMT", "VIDIOC_S_FMT",
...@@ -1288,7 +1297,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1288,7 +1297,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
em28xx_videodbg("%s: requested %dx%d", em28xx_videodbg("%s: requested %dx%d\n",
cmd == cmd ==
VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
"VIDIOC_S_FMT", format->fmt.pix.width, "VIDIOC_S_FMT", format->fmt.pix.width,
...@@ -1347,7 +1356,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1347,7 +1356,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
format->fmt.pix.field = V4L2_FIELD_INTERLACED; format->fmt.pix.field = V4L2_FIELD_INTERLACED;
em28xx_videodbg("%s: returned %dx%d (%d, %d)", em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
cmd == cmd ==
VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
"VIDIOC_S_FMT", format->fmt.pix.width, "VIDIOC_S_FMT", format->fmt.pix.width,
...@@ -1359,13 +1368,13 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1359,13 +1368,13 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
for (i = 0; i < dev->num_frames; i++) for (i = 0; i < dev->num_frames; i++)
if (dev->frame[i].vma_use_count) { if (dev->frame[i].vma_use_count) {
em28xx_videodbg("VIDIOC_S_FMT failed. " em28xx_videodbg("VIDIOC_S_FMT failed. "
"Unmap the buffers first."); "Unmap the buffers first.\n");
return -EINVAL; return -EINVAL;
} }
/* stop io in case it is already in progress */ /* stop io in case it is already in progress */
if (dev->stream == STREAM_ON) { if (dev->stream == STREAM_ON) {
em28xx_videodbg("VIDIOC_SET_FMT: interupting stream"); em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
if ((ret = em28xx_stream_interrupt(dev))) if ((ret = em28xx_stream_interrupt(dev)))
return ret; return ret;
} }
...@@ -1405,18 +1414,18 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1405,18 +1414,18 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
if (dev->io == IO_READ) { if (dev->io == IO_READ) {
em28xx_videodbg ("method is set to read;" em28xx_videodbg ("method is set to read;"
" close and open the device again to" " close and open the device again to"
" choose the mmap I/O method"); " choose the mmap I/O method\n");
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < dev->num_frames; i++) for (i = 0; i < dev->num_frames; i++)
if (dev->frame[i].vma_use_count) { if (dev->frame[i].vma_use_count) {
em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped"); em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
return -EINVAL; return -EINVAL;
} }
if (dev->stream == STREAM_ON) { if (dev->stream == STREAM_ON) {
em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream"); em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
if ((ret = em28xx_stream_interrupt(dev))) if ((ret = em28xx_stream_interrupt(dev)))
return ret; return ret;
} }
...@@ -1430,7 +1439,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, ...@@ -1430,7 +1439,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
dev->frame_current = NULL; dev->frame_current = NULL;
em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i", em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
rb->count); rb->count);
dev->io = rb->count ? IO_MMAP : IO_NONE; dev->io = rb->count ? IO_MMAP : IO_NONE;
return 0; return 0;
......
...@@ -90,6 +90,8 @@ struct msp3400c { ...@@ -90,6 +90,8 @@ struct msp3400c {
int stereo; int stereo;
int nicam_on; int nicam_on;
int acb; int acb;
int in_scart;
int i2s_mode;
int main, second; /* sound carrier */ int main, second; /* sound carrier */
int input; int input;
int source; /* see msp34xxg_set_source */ int source; /* see msp34xxg_set_source */
...@@ -364,12 +366,40 @@ static struct CARRIER_DETECT carrier_detect_65[] = { ...@@ -364,12 +366,40 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) #define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- *
* bits 9 8 5 - SCART DSP input Select:
* 0 0 0 - SCART 1 to DSP input (reset position)
* 0 1 0 - MONO to DSP input
* 1 0 0 - SCART 2 to DSP input
* 1 1 1 - Mute DSP input
*
* bits 11 10 6 - SCART 1 Output Select:
* 0 0 0 - undefined (reset position)
* 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
* 1 0 0 - MONO input to SCART 1 Output
* 1 1 0 - SCART 1 DA to SCART 1 Output
* 0 0 1 - SCART 2 DA to SCART 1 Output
* 0 1 1 - SCART 1 Input to SCART 1 Output
* 1 1 1 - Mute SCART 1 Output
*
* bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART):
* 0 0 0 - SCART 1 DA to SCART 2 Output (reset position)
* 0 1 0 - SCART 1 Input to SCART 2 Output
* 1 0 0 - MONO input to SCART 2 Output
* 0 0 1 - SCART 2 DA to SCART 2 Output
* 0 1 1 - SCART 2 Input to SCART 2 Output
* 1 1 0 - Mute SCART 2 Output
*
* Bits 4 to 0 should be zero.
* ----------------------------------------------------------------------- */
static int scarts[3][9] = { static int scarts[3][9] = {
/* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
/* SCART DSP Input select */
{ 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
/* SCART1 Output select */
{ 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
/* SCART2 Output select */
{ 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
}; };
...@@ -381,13 +411,23 @@ static void msp3400c_set_scart(struct i2c_client *client, int in, int out) ...@@ -381,13 +411,23 @@ static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
{ {
struct msp3400c *msp = i2c_get_clientdata(client); struct msp3400c *msp = i2c_get_clientdata(client);
msp->in_scart=in;
if (in<=2) {
if (-1 == scarts[out][in]) if (-1 == scarts[out][in])
return; return;
dprintk("msp34xx: scart switch: %s => %d\n", scart_names[in], out);
msp->acb &= ~scarts[out][SCART_MASK]; msp->acb &= ~scarts[out][SCART_MASK];
msp->acb |= scarts[out][in]; msp->acb |= scarts[out][in];
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb); } else
msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
dprintk("msp34xx: scart switch: %s => %d (ACB=0x%04x)\n",
scart_names[in], out, msp->acb);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
} }
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -1235,7 +1275,8 @@ static int msp3410d_thread(void *data) ...@@ -1235,7 +1275,8 @@ static int msp3410d_thread(void *data)
msp3400c_setbass(client, msp->bass); msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble); msp3400c_settreble(client, msp->treble);
msp3400c_setvolume(client, msp->muted, msp->left, msp->right); msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb); msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
msp3400c_restore_dfp(client); msp3400c_restore_dfp(client);
/* monitor tv audio mode */ /* monitor tv audio mode */
...@@ -1275,6 +1316,8 @@ static int msp34xxg_reset(struct i2c_client *client) ...@@ -1275,6 +1316,8 @@ static int msp34xxg_reset(struct i2c_client *client)
0x0f20 /* mute DSP input, mute SCART 1 */)) 0x0f20 /* mute DSP input, mute SCART 1 */))
return -1; return -1;
msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
/* step-by-step initialisation, as described in the manual */ /* step-by-step initialisation, as described in the manual */
modus = msp34xx_modus(msp->norm); modus = msp34xx_modus(msp->norm);
std = msp34xx_standard(msp->norm); std = msp34xx_standard(msp->norm);
...@@ -1371,6 +1414,8 @@ static int msp34xxg_thread(void *data) ...@@ -1371,6 +1414,8 @@ static int msp34xxg_thread(void *data)
0x13, /* ACB */ 0x13, /* ACB */
msp->acb)) msp->acb))
return -1; return -1;
msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
} }
dprintk("msp34xxg: thread: exit\n"); dprintk("msp34xxg: thread: exit\n");
return 0; return 0;
...@@ -1539,6 +1584,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) ...@@ -1539,6 +1584,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
msp->treble = 32768; msp->treble = 32768;
msp->input = -1; msp->input = -1;
msp->muted = 0; msp->muted = 0;
msp->i2s_mode = 0;
for (i = 0; i < DFP_COUNT; i++) for (i = 0; i < DFP_COUNT; i++)
msp->dfp_regs[i] = -1; msp->dfp_regs[i] = -1;
...@@ -1735,6 +1781,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode) ...@@ -1735,6 +1781,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
} }
} }
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
struct msp3400c *msp = i2c_get_clientdata(client); struct msp3400c *msp = i2c_get_clientdata(client);
...@@ -1745,6 +1792,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -1745,6 +1792,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case AUDC_SET_INPUT: case AUDC_SET_INPUT:
dprintk("msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); dprintk("msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
if (*sarg == msp->input) if (*sarg == msp->input)
break; break;
msp->input = *sarg; msp->input = *sarg;
...@@ -1923,6 +1971,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -1923,6 +1971,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break; break;
} }
/* msp34xx specific */
case MSP_SET_MATRIX:
{
struct msp_matrix *mspm = arg;
dprintk("msp34xx: MSP_SET_MATRIX\n");
msp3400c_set_scart(client, mspm->input, mspm->output);
break;
}
/* --- v4l2 ioctls --- */ /* --- v4l2 ioctls --- */
case VIDIOC_S_STD: case VIDIOC_S_STD:
{ {
...@@ -1941,6 +1999,33 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -1941,6 +1999,33 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0; return 0;
} }
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
if (i->index != 0)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_TUNER;
switch (i->index) {
case AUDIO_RADIO:
strcpy(i->name,"Radio");
break;
case AUDIO_EXTERN_1:
strcpy(i->name,"Extern 1");
break;
case AUDIO_EXTERN_2:
strcpy(i->name,"Extern 2");
break;
case AUDIO_TUNER:
strcpy(i->name,"Television");
break;
default:
return -EINVAL;
}
return 0;
}
case VIDIOC_G_AUDIO: case VIDIOC_G_AUDIO:
{ {
struct v4l2_audio *a = arg; struct v4l2_audio *a = arg;
...@@ -2032,13 +2117,44 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -2032,13 +2117,44 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break; break;
} }
/* msp34xx specific */ case VIDIOC_G_AUDOUT:
case MSP_SET_MATRIX:
{ {
struct msp_matrix *mspm = arg; struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
memset(a,0,sizeof(*a));
switch (a->index) {
case 0:
strcpy(a->name,"Scart1 Out");
break;
case 1:
strcpy(a->name,"Scart2 Out");
break;
case 2:
strcpy(a->name,"I2S Out");
break;
default:
return -EINVAL;
}
break;
}
case VIDIOC_S_AUDOUT:
{
struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
if (a->index<0||a->index>2)
return -EINVAL;
if (a->index==2) {
if (a->mode == V4L2_AUDMODE_32BITS)
msp->i2s_mode=1;
else
msp->i2s_mode=0;
}
printk("Setting audio out on msp34xx to input %i, mode %i\n",a->index,msp->i2s_mode);
msp3400c_set_scart(client,msp->in_scart,a->index);
dprintk("msp34xx: MSP_SET_MATRIX\n");
msp3400c_set_scart(client, mspm->input, mspm->output);
break; break;
} }
......
...@@ -885,6 +885,7 @@ struct v4l2_audio ...@@ -885,6 +885,7 @@ struct v4l2_audio
/* Flags for the 'mode' field */ /* Flags for the 'mode' field */
#define V4L2_AUDMODE_AVL 0x00001 #define V4L2_AUDMODE_AVL 0x00001
#define V4L2_AUDMODE_32BITS 0x00002
struct v4l2_audioout struct v4l2_audioout
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment