From 37e435002c62d00de4f01da3de1af44b3fd8773f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 11 Nov 2008 18:04:30 +0100 Subject: uvcvideo: Use {get|set}_unaligned_le32 macros From: Laurent Pinchart Replace combination of endianess conversion and unaligned access macros with {get|set}_unaligned_*. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_video.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 987e110fe..54bc53bea 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -142,14 +142,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]); ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]); ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]); - ctrl->dwMaxVideoFrameSize = - le32_to_cpu(get_unaligned((__le32 *)&data[18])); - ctrl->dwMaxPayloadTransferSize = - le32_to_cpu(get_unaligned((__le32 *)&data[22])); + ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); + ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); if (size == 34) { - ctrl->dwClockFrequency = - le32_to_cpu(get_unaligned((__le32 *)&data[26])); + ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); ctrl->bmFramingInfo = data[30]; ctrl->bPreferedVersion = data[31]; ctrl->bMinVersion = data[32]; @@ -197,14 +194,11 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video, /* Note: Some of the fields below are not required for IN devices (see * UVC spec, 4.3.1.1), but we still copy them in case support for OUT * devices is added in the future. */ - put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize), - (__le32 *)&data[18]); - put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize), - (__le32 *)&data[22]); + put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); + put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); if (size == 34) { - put_unaligned(cpu_to_le32(ctrl->dwClockFrequency), - (__le32 *)&data[26]); + put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); data[30] = ctrl->bmFramingInfo; data[31] = ctrl->bPreferedVersion; data[32] = ctrl->bMinVersion; -- cgit v1.2.3 From 347a206147fa5c4958c0881ef90d14362978d80a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 11 Nov 2008 18:11:28 +0100 Subject: uvcvideo: Fix unaligned memory access. From: Michael Hennerich Use the unaligned memory access macros when accessing unaligned memory. Priority: normal Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_driver.c | 39 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 046b98871..0a0ef6611 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -452,20 +453,20 @@ static int uvc_parse_format(struct uvc_device *dev, frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; - frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]); - frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]); - frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]); - frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]); + frame->wWidth = get_unaligned_le16(&buffer[5]); + frame->wHeight = get_unaligned_le16(&buffer[7]); + frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); + frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); if (ftype != VS_FRAME_FRAME_BASED) { frame->dwMaxVideoFrameBufferSize = - le32_to_cpup((__le32 *)&buffer[17]); + get_unaligned_le32(&buffer[17]); frame->dwDefaultFrameInterval = - le32_to_cpup((__le32 *)&buffer[21]); + get_unaligned_le32(&buffer[21]); frame->bFrameIntervalType = buffer[25]; } else { frame->dwMaxVideoFrameBufferSize = 0; frame->dwDefaultFrameInterval = - le32_to_cpup((__le32 *)&buffer[17]); + get_unaligned_le32(&buffer[17]); frame->bFrameIntervalType = buffer[21]; } frame->dwFrameInterval = *intervals; @@ -488,7 +489,7 @@ static int uvc_parse_format(struct uvc_device *dev, * some other divisions by zero which could happen. */ for (i = 0; i < n; ++i) { - interval = le32_to_cpup((__le32 *)&buffer[26+4*i]); + interval = get_unaligned_le32(&buffer[26+4*i]); *(*intervals)++ = interval ? interval : 1; } @@ -832,8 +833,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unit->type = VC_EXTENSION_UNIT; memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; - unit->extension.bNrInPins = - le16_to_cpup((__le16 *)&buffer[21]); + unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; memcpy(unit->extension.baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; @@ -877,8 +877,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]); - dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]); + dev->uvc_version = get_unaligned_le16(&buffer[3]); + dev->clock_frequency = get_unaligned_le32(&buffer[7]); /* Parse all USB Video Streaming interfaces. */ for (i = 0; i < n; ++i) { @@ -905,7 +905,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, /* Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit. */ - type = le16_to_cpup((__le16 *)&buffer[4]); + type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL %d has invalid " @@ -947,11 +947,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev, term->camera.bControlSize = n; term->camera.bmControls = (__u8 *)term + sizeof *term; term->camera.wObjectiveFocalLengthMin = - le16_to_cpup((__le16 *)&buffer[8]); + get_unaligned_le16(&buffer[8]); term->camera.wObjectiveFocalLengthMax = - le16_to_cpup((__le16 *)&buffer[10]); + get_unaligned_le16(&buffer[10]); term->camera.wOcularFocalLength = - le16_to_cpup((__le16 *)&buffer[12]); + get_unaligned_le16(&buffer[12]); memcpy(term->camera.bmControls, &buffer[15], n); } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) { term->media.bControlSize = n; @@ -987,7 +987,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, /* Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit. */ - type = le16_to_cpup((__le16 *)&buffer[4]); + type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d OUTPUT_TERMINAL %d has invalid " @@ -1061,7 +1061,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->type = buffer[2]; unit->processing.bSourceID = buffer[4]; unit->processing.wMaxMultiplier = - le16_to_cpup((__le16 *)&buffer[5]); + get_unaligned_le16(&buffer[5]); unit->processing.bControlSize = buffer[7]; unit->processing.bmControls = (__u8 *)unit + sizeof *unit; memcpy(unit->processing.bmControls, &buffer[8], n); @@ -1096,8 +1096,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->type = buffer[2]; memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; - unit->extension.bNrInPins = - le16_to_cpup((__le16 *)&buffer[21]); + unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; memcpy(unit->extension.baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; -- cgit v1.2.3 From 2a9e9cf9da405aca4f7303353c68de82e180fc2d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 12 Nov 2008 15:46:43 +0100 Subject: uvcvideo: Commit streaming parameters when enabling the video stream. From: Laurent Pinchart Sonix-based cameras seem to require the host to commit video streaming parameters before selecting the alternate endpoint. While most applications issue a VIDIOC_S_FMT ioctl before starting streaming, this is not required by the V4L2 specification. The problem has been noticed on Ubuntu 8.10 with applications using libv4l. The library blocks VIDIOC_S_FMT calls when the requested format is identical to the currently selected format. As the driver commits video streaming parameters when initialising the device, only the first run of a libv4l-enabled application would succeed. For the sake of completeness, experiment showed that the camera keeps sending 12 bytes isochronous packets (header only, no data) without toggling the FID bit if video streaming parameters haven't been committed before selecting the alternate endpoint. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_v4l2.c | 7 ------- linux/drivers/media/video/uvc/uvc_video.c | 9 +++++---- 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index 5588698e2..b4191cb21 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -252,9 +252,6 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, if (ret < 0) return ret; - if ((ret = uvc_commit_video(video, &probe)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -315,10 +312,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, if ((ret = uvc_probe_video(video, &probe)) < 0) return ret; - /* Commit the new settings. */ - if ((ret = uvc_commit_video(video, &probe)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); /* Return the actual frame period. */ diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 54bc53bea..3be776a47 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -893,7 +893,7 @@ int uvc_video_resume(struct uvc_video_device *video) video->frozen = 0; - if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) { + if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) { uvc_queue_enable(&video->queue, 0); return ret; } @@ -974,11 +974,8 @@ int uvc_video_init(struct uvc_video_device *video) break; } - /* Commit the default settings. */ probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; - if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0) - return ret; video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -1018,6 +1015,10 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) return ret; + /* Commit the streaming parameters. */ + if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) + return ret; + return uvc_init_video(video, GFP_KERNEL); } -- cgit v1.2.3 From f7addb7035dedd9ba701c586fec16b234dde4a77 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 17 Nov 2008 22:32:11 +0100 Subject: uvcvideo: Fix printk badness when printing ioctl names From: Laurent Pinchart Add a trailing newline character after calling v4l_printk_ioctl() to avoid messing the kernel log up and merge the uvc_v4l2_ioctl message with the ioctl name. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_v4l2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index b4191cb21..95eb6f3ad 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -470,9 +470,6 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct uvc_fh *handle = (struct uvc_fh *)file->private_data; int ret = 0; - if (uvc_trace_param & UVC_TRACE_IOCTL) - v4l_printk_ioctl(cmd); - switch (cmd) { /* Query capabilities */ case VIDIOC_QUERYCAP: @@ -989,7 +986,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) static int uvc_v4l2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n"); + if (uvc_trace_param & UVC_TRACE_IOCTL) { + uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl("); + v4l_printk_ioctl(cmd); + printk(")\n"); + } + return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); } -- cgit v1.2.3 From 94af51fcec623e24c6a1e9fdf8130b1b70d7dd08 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 08:07:45 -0200 Subject: new email address From: Jelle Foks Please accept this patch to refer to my new email address Priority: normal Signed-off-by: Jelle Foks Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx23885/cx23885-417.c | 2 +- linux/drivers/media/video/cx88/cx88-blackbird.c | 4 ++-- linux/drivers/media/video/cx88/cx88-mpeg.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index d98e64545..dfe8ddbce 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -2,7 +2,7 @@ * * Support for a cx23417 mpeg encoder via cx23885 host port. * - * (c) 2004 Jelle Foks + * (c) 2004 Jelle Foks * (c) 2004 Gerd Knorr * (c) 2008 Steven Toth * - CX23885/7/8 support diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c index 3d2afe195..b090c6620 100644 --- a/linux/drivers/media/video/cx88/cx88-blackbird.c +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -3,7 +3,7 @@ * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. * - * (c) 2004 Jelle Foks + * (c) 2004 Jelle Foks * (c) 2004 Gerd Knorr * * (c) 2005-2006 Mauro Carvalho Chehab @@ -39,7 +39,7 @@ #include "cx88.h" MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); -MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); +MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); static unsigned int mpegbufs = 32; diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index dbad45a35..9d407ac26 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -3,7 +3,7 @@ * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. * - * (c) 2004 Jelle Foks + * (c) 2004 Jelle Foks * (c) 2004 Chris Pascoe * (c) 2004 Gerd Knorr * @@ -34,7 +34,7 @@ /* ------------------------------------------------------------------ */ MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards"); -MODULE_AUTHOR("Jelle Foks "); +MODULE_AUTHOR("Jelle Foks "); MODULE_AUTHOR("Chris Pascoe "); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 62b145c464b403e8ca5d1e17af30367298d5c6a0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Nov 2008 07:17:44 -0200 Subject: Avoid having two concurrent control URB's From: Mauro Carvalho Chehab Now that we have a polling task for IR, there's a race condition, since IR can be polling while other operations are being doing. Also, we are now sharing the same urb_buf for both read and write control urb operations. So, we need a mutex. Thanks to Davin Heitmueller for warning me. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 12 ++++++++++-- linux/drivers/media/video/em28xx/em28xx-video.c | 1 + linux/drivers/media/video/em28xx/em28xx.h | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index ef6830cd5..490afcba0 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -76,18 +76,22 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, em28xx_regdbg("req=%02x, reg=%02x ", req, reg); + mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { if (reg_debug) printk(" failed!\n"); + mutex_unlock(&dev->ctrl_urb_lock); return ret; } if (len) memcpy(buf, dev->urb_buf, len); + mutex_unlock(&dev->ctrl_urb_lock); + if (reg_debug) { printk("%02x values: ", ret); for (byte = 0; byte < len; byte++) @@ -112,16 +116,18 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) em28xx_regdbg("req=%02x, reg=%02x:", req, reg); + mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, 1, HZ); + val = dev->urb_buf[0]; + mutex_unlock(&dev->ctrl_urb_lock); + if (ret < 0) { printk(" failed!\n"); return ret; } - val = dev->urb_buf[0]; - if (reg_debug) printk("%02x\n", (unsigned char) val); @@ -156,10 +162,12 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, printk("\n"); } + mutex_lock(&dev->ctrl_urb_lock); memcpy(dev->urb_buf, buf, len); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); + mutex_unlock(&dev->ctrl_urb_lock); if (dev->wait_after_write) msleep(dev->wait_after_write); diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 625c9dea1..70d0bd086 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -2017,6 +2017,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->udev = udev; mutex_init(&dev->lock); + mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); init_waitqueue_head(&dev->open); init_waitqueue_head(&dev->wait_frame); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 2e108be19..2ef7d0224 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -450,6 +450,7 @@ struct em28xx { /* locks */ struct mutex lock; + struct mutex ctrl_urb_lock; /* protects urb_buf */ /* spinlock_t queue_lock; */ struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; -- cgit v1.2.3 From 89163963726ca703e129cb9c2e38206d1f8a2cb4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Nov 2008 09:22:28 -0200 Subject: Make use of the em28xx chip configuration register to determine whether From: Devin Heitmueller we have AC97 audio, I2S audio, or no audio support at all. Thanks for Ray Lu from Empia for providing the em2860/em2880 datasheet. Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-reg.h | 10 +++++++ linux/drivers/media/video/em28xx/em28xx-video.c | 35 ++++++++++++++++++++++++- linux/drivers/media/video/em28xx/em28xx.h | 8 ++++++ 3 files changed, 52 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index 491d66abe..12c9132b0 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -17,6 +17,16 @@ /* em28xx registers */ +#define EM28XX_R00_CHIPCFG 0x00 + +/* em28xx Chip Configuration 0x00 */ +#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 +#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 +#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x30 +#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x20 +#define EM28XX_CHIPCFG_AC97 0x10 +#define EM28XX_CHIPCFG_AUDIOMASK 0x30 + /* GPIO/GPO registers */ #define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 70d0bd086..d406fc224 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1990,16 +1990,49 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, int em28xx_supports_audio_extension(struct em28xx *dev) { + int rc; + /* The chip dictates whether we support the Empia analog audio extension */ switch (dev->chip_id) { case CHIP_ID_EM2874: - /* Either a digital-only device or provides AC97 audio */ + /* Digital only device - no analog support */ + dev->audio_mode = EM28XX_NO_AUDIO; return 0; + case CHIP_ID_EM2860: case CHIP_ID_EM2883: default: + /* See how this device is configured */ + rc = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); + if (rc & EM28XX_CHIPCFG_VENDOR_AUDIO) { + switch(rc & EM28XX_CHIPCFG_AUDIOMASK) { + case EM28XX_CHIPCFG_AC97: + em28xx_info("AC97 audio (5 sample rates)\n"); + dev->audio_mode = EM28XX_AC97; + break; + case EM28XX_CHIPCFG_I2S_3_SAMPRATES: + em28xx_info("I2S Audio (3 sample rates)\n"); + dev->audio_mode = EM28XX_I2S_3_SAMPLE_RATES; + break; + case EM28XX_CHIPCFG_I2S_5_SAMPRATES: + em28xx_info("I2S Audio (5 sample rates)\n"); + dev->audio_mode = EM28XX_I2S_5_SAMPLE_RATES; + break; + default: + em28xx_info("No audio support detected\n"); + dev->audio_mode = EM28XX_NO_AUDIO; + return 0; + } + } else { + em28xx_info("USB Audio class device\n"); + return 0; + } + /* The em28xx audio extension needs to be loaded */ return 1; } + + /* We should never reach this point */ + return 0; } /* diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 2ef7d0224..d272598c9 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -257,6 +257,13 @@ enum enum28xx_itype { EM28XX_RADIO, }; +enum em28xx_audio_mode { + EM28XX_NO_AUDIO, + EM28XX_I2S_3_SAMPLE_RATES, + EM28XX_I2S_5_SAMPLE_RATES, + EM28XX_AC97, +}; + enum em28xx_amux { EM28XX_AMUX_VIDEO, EM28XX_AMUX_LINE_IN, @@ -412,6 +419,7 @@ struct em28xx { u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; + enum em28xx_audio_mode audio_mode; int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ -- cgit v1.2.3 From d66eb05b55e0b7dee53b5abcdacd324c74289e84 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Nov 2008 12:08:53 -0200 Subject: em28xx: remove two amux entries used only on one card From: Mauro Carvalho Chehab This patch parepares for an audio refactor patch that auto-detects ac97 chips. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 57c91838e..fbbe5ab0c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -946,11 +946,11 @@ struct em28xx_board em28xx_boards[] = { }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_AC97_LINE_IN, + .amux = EM28XX_AMUX_LINE_IN, }, { /* S-video has not been tested yet */ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_AC97_LINE_IN, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2881_BOARD_DNT_DA2_HYBRID] = { -- cgit v1.2.3 From 460f427f45af6f9f477339f8b689d6576da41127 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Nov 2008 12:10:50 -0200 Subject: em28xx: replace magic numbers to something more meaningful From: Mauro Carvalho Chehab audio mux entries were described by 0 and 1 magic numers. Use an enum alias for each entry type. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 252 ++++++++++++------------ 1 file changed, 126 insertions(+), 126 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index fbbe5ab0c..01765c33f 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -59,7 +59,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2800_BOARD_UNKNOWN] = { @@ -71,11 +71,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_UNKNOWN] = { @@ -91,7 +91,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { @@ -104,11 +104,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { @@ -120,15 +120,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_USB_2] = { @@ -140,15 +140,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { @@ -183,15 +183,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { @@ -204,15 +204,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { @@ -226,15 +226,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_GADMEI_UTV310] = { @@ -247,15 +247,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { @@ -268,15 +268,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = 2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = 9, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_DVC_100] = { @@ -287,11 +287,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { @@ -301,7 +301,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2821_BOARD_PROLINK_PLAYTV_USB2] = { @@ -315,15 +315,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2821_BOARD_SUPERCOMP_USB_2] = { @@ -339,15 +339,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2821_BOARD_USBGEAR_VD204] = { @@ -358,11 +358,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_NETGMBH_CAM] = { @@ -373,7 +373,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2860_BOARD_TYPHOON_DVD_MAKER] = { @@ -384,11 +384,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_GADMEI_UTV330] = { @@ -401,15 +401,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_TERRATEC_HYBRID_XS] = { @@ -421,15 +421,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_KWORLD_PVRTV_300U] = { @@ -441,15 +441,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { @@ -460,15 +460,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_PLEXTOR_PX_TV100U] = { @@ -481,15 +481,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2870_BOARD_TERRATEC_XS] = { @@ -531,15 +531,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { @@ -553,15 +553,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { @@ -574,7 +574,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, @@ -582,7 +582,7 @@ struct em28xx_board em28xx_boards[] = { }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { @@ -598,15 +598,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { @@ -622,15 +622,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { @@ -646,15 +646,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { @@ -667,15 +667,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, /* maybe there's a reason behind it why Terratec sells the Hybrid XS @@ -690,15 +690,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_MSI_VOX_USB_2] = { @@ -714,15 +714,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE4, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_TERRATEC_CINERGY_200] = { @@ -735,15 +735,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_GRABBEEX_USB2800] = { @@ -754,11 +754,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { @@ -771,15 +771,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_KWORLD_USB2800] = { @@ -792,15 +792,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { @@ -811,11 +811,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_VGEAR_POCKETTV] = { @@ -828,15 +828,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { @@ -869,7 +869,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD] = { @@ -881,15 +881,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { @@ -901,15 +901,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_KWORLD_DVB_305U] = { @@ -921,15 +921,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_KWORLD_DVB_310U] = { @@ -962,15 +962,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { @@ -982,15 +982,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { @@ -1003,15 +1003,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_KWORLD_VS_DVBT] = { @@ -1023,15 +1023,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_TERRATEC_HYBRID_XS] = { @@ -1043,15 +1043,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2883_BOARD_KWORLD_HYBRID_A316] = { @@ -1064,15 +1064,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { -- cgit v1.2.3 From 882f0f5cc3bf4bcd00923aad0cacf002d8009e06 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Nov 2008 13:01:33 -0200 Subject: em28xx: Improve audio handling From: Mauro Carvalho Chehab This patch properly implements audio handling on em28xx. Before this patch, it was assumed that every device has an Empia 202 audio chip. However, this is not true. After this patch, specific AC97 chipset setup and configurations can be done. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 253 +++++++++++++++++++----- linux/drivers/media/video/em28xx/em28xx-video.c | 63 +----- linux/drivers/media/video/em28xx/em28xx.h | 27 ++- 3 files changed, 226 insertions(+), 117 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 490afcba0..3a6252a8b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -223,16 +223,71 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, return em28xx_write_regs(dev, reg, &newval, 1); } +/* + * em28xx_is_ac97_ready() + * Checks if ac97 is ready + */ +static int em28xx_is_ac97_ready(struct em28xx *dev) +{ + int ret, i; + + /* Wait up to 50 ms for AC97 command to complete */ + for (i = 0; i < 10; i++, msleep(5)) { + ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); + if (ret < 0) + return ret; + + if (!(ret & 0x01)) + return 0; + } + + em28xx_warn("AC97 command still being executed: not handled properly!\n"); + return -EBUSY; +} + +/* + * em28xx_read_ac97() + * write a 16 bit value to the specified AC97 address (LSB first!) + */ +static int em28xx_read_ac97(struct em28xx *dev, u8 reg) +{ + int ret; + u8 addr = (reg & 0x7f) | 0x80; + u16 val; + + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); + if (ret < 0) + return ret; + + ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB, + (u8 *)&val, sizeof(val)); + + if (ret < 0) + return ret; + return le16_to_cpu(val); +} + /* * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */ -static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) +static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) { - int ret, i; + int ret; u8 addr = reg & 0x7f; + __le16 value; + + value = cpu_to_le16(val); + + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; - ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2); + ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2); if (ret < 0) return ret; @@ -240,25 +295,36 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) if (ret < 0) return ret; - /* Wait up to 50 ms for AC97 command to complete */ - for (i = 0; i < 10; i++) { - ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); - if (ret < 0) - return ret; + return 0; +} - if (!(ret & 0x01)) - return 0; - msleep(5); +static int set_ac97_em202_input(struct em28xx *dev) +{ + int ret; + u16 enable = 0x0808; /* 12 dB attenuation Left/Right */ + u16 disable = 0x8808; /* bit 15 - mute volumme */ + u16 video, line; + + if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) { + video = enable; + line = disable; + } else { + video = disable; + line = enable; } - em28xx_warn("AC97 command still being executed: not handled properly!\n"); - return 0; + + /* Sets em202 AC97 mixer registers */ + ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); + if (ret < 0) + return ret; + + ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); + + return ret; } static int em28xx_set_audio_source(struct em28xx *dev) { - static char *enable = "\x08\x08"; - static char *disable = "\x08\x88"; - char *video = enable, *line = disable; int ret; u8 input; @@ -280,18 +346,8 @@ static int em28xx_set_audio_source(struct em28xx *dev) case EM28XX_AMUX_VIDEO: input = EM28XX_AUDIO_SRC_TUNER; break; - case EM28XX_AMUX_LINE_IN: + default: input = EM28XX_AUDIO_SRC_LINE; - video = disable; - line = enable; - break; - case EM28XX_AMUX_AC97_VIDEO: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - video = disable; - line = enable; break; } } @@ -301,33 +357,36 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; msleep(5); - /* Sets AC97 mixer registers - This is seems to be needed, even for non-ac97 configs - */ - ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); - if (ret < 0) - return ret; - - ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + break; + case EM28XX_AC97_OTHER: + /* We don't know how to handle this chip. + Let's hope it is close enough to em202 to work + */ + case EM28XX_AC97_EM202: + ret = set_ac97_em202_input(dev); + break; + } - return ret; + return 0; } int em28xx_audio_analog_set(struct em28xx *dev) { int ret; - char s[2] = { 0x00, 0x00 }; u8 xclk = 0x07; - s[0] |= 0x1f - dev->volume; - s[1] |= 0x1f - dev->volume; + if (!dev->audio_mode.has_audio) + return 0; - /* Mute */ - s[1] |= 0x80; - ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + /* Mute */ + ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000); - if (ret < 0) - return ret; + if (ret < 0) + return ret; + } if (dev->has_12mhz_i2s) xclk |= 0x20; @@ -343,15 +402,113 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); - /* Unmute device */ - if (!dev->mute) - s[1] &= ~0x80; - ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); + /* Sets volume */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + int vol; + + /* LSB: left channel - both channels with the same level */ + vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); + + /* Mute device, if needed */ + if (dev->mute) + vol |= 0x8000; + + /* Sets volume */ + ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, vol); + } return ret; } EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); +int em28xx_audio_setup(struct em28xx *dev) +{ + int vid1, vid2, feat, cfg; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* Digital only device - don't load any alsa module */ + dev->audio_mode.has_audio = 0; + dev->has_audio_class = 0; + dev->has_alsa_audio = 0; + return 0; + } + + /* If device doesn't support Usb Audio Class, use vendor class */ + if (!dev->has_audio_class) + dev->has_alsa_audio = 1; + + dev->audio_mode.has_audio = 1; + + /* See how this device is configured */ + cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); + if (cfg < 0) + cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ + else + em28xx_info("Config register raw data: 0x%02x\n", cfg); + + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_3_SAMPRATES) { + em28xx_info("I2S Audio (3 sample rates)\n"); + dev->audio_mode.i2s_3rates = 1; + } + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_5_SAMPRATES) { + em28xx_info("I2S Audio (5 sample rates)\n"); + dev->audio_mode.i2s_5rates = 1; + } + + if (!(cfg & EM28XX_CHIPCFG_AC97)) { + dev->audio_mode.ac97 = EM28XX_NO_AC97; + goto init_audio; + } + + dev->audio_mode.ac97 = EM28XX_AC97_OTHER; + + vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1); + if (vid1 < 0) { + /* Device likely doesn't support AC97 */ + em28xx_warn("AC97 chip type couldn't be determined\n"); + goto init_audio; + } + + vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2); + if (vid2 < 0) + goto init_audio; + + dev->audio_mode.ac97_vendor_id1 = vid1; + dev->audio_mode.ac97_vendor_id2 = vid2; + em28xx_warn("AC97 vendor ID = %04x:%04x\n", vid1, vid2); + + feat = em28xx_read_ac97(dev, AC97_RESET); + if (feat < 0) + goto init_audio; + + dev->audio_mode.ac97_feat = feat; + em28xx_warn("AC97 features = 0x%04x\n", feat); + + if ((vid1 == 0xffff) && (vid2 == 0xffff) && (feat == 0x6a90)) + dev->audio_mode.ac97 = EM28XX_AC97_EM202; + +init_audio: + /* Reports detected AC97 processor */ + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + em28xx_info("No AC97 audio processor\n"); + break; + case EM28XX_AC97_EM202: + em28xx_info("Empia 202 AC97 audio processor detected\n"); + break; + case EM28XX_AC97_OTHER: + em28xx_warn("Unknown AC97 audio processor detected!\n"); + break; + default: + break; + } + + return em28xx_audio_analog_set(dev); +} +EXPORT_SYMBOL_GPL(em28xx_audio_setup); + int em28xx_colorlevels_set_default(struct em28xx *dev) { em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index d406fc224..88bff6bd7 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1988,53 +1988,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } -int em28xx_supports_audio_extension(struct em28xx *dev) -{ - int rc; - - /* The chip dictates whether we support the Empia analog audio - extension */ - switch (dev->chip_id) { - case CHIP_ID_EM2874: - /* Digital only device - no analog support */ - dev->audio_mode = EM28XX_NO_AUDIO; - return 0; - case CHIP_ID_EM2860: - case CHIP_ID_EM2883: - default: - /* See how this device is configured */ - rc = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - if (rc & EM28XX_CHIPCFG_VENDOR_AUDIO) { - switch(rc & EM28XX_CHIPCFG_AUDIOMASK) { - case EM28XX_CHIPCFG_AC97: - em28xx_info("AC97 audio (5 sample rates)\n"); - dev->audio_mode = EM28XX_AC97; - break; - case EM28XX_CHIPCFG_I2S_3_SAMPRATES: - em28xx_info("I2S Audio (3 sample rates)\n"); - dev->audio_mode = EM28XX_I2S_3_SAMPLE_RATES; - break; - case EM28XX_CHIPCFG_I2S_5_SAMPRATES: - em28xx_info("I2S Audio (5 sample rates)\n"); - dev->audio_mode = EM28XX_I2S_5_SAMPLE_RATES; - break; - default: - em28xx_info("No audio support detected\n"); - dev->audio_mode = EM28XX_NO_AUDIO; - return 0; - } - } else { - em28xx_info("USB Audio class device\n"); - return 0; - } - /* The em28xx audio extension needs to be loaded */ - return 1; - } - - /* We should never reach this point */ - return 0; -} - /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -2083,11 +2036,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_card_setup(dev); /* Configure audio */ - errCode = em28xx_audio_analog_set(dev); + errCode = em28xx_audio_setup(dev); if (errCode < 0) { - em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n", + em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", __func__, errCode); - return errCode; } /* configure the device */ @@ -2373,17 +2325,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, em28xx_info("Found %s\n", em28xx_boards[dev->model].name); - if (dev->has_audio_class == 0) { - /* We don't have a USB audio class, let's see if we support - ALSA Audio */ - dev->has_alsa_audio = em28xx_supports_audio_extension(dev); - if (dev->has_alsa_audio) - printk(KERN_INFO DRIVER_NAME " supports alsa audio\n"); - } else { - printk(KERN_INFO DRIVER_NAME " has usb audio class\n"); - } - - /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index d272598c9..06d5872f1 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -257,18 +257,28 @@ enum enum28xx_itype { EM28XX_RADIO, }; -enum em28xx_audio_mode { - EM28XX_NO_AUDIO, - EM28XX_I2S_3_SAMPLE_RATES, - EM28XX_I2S_5_SAMPLE_RATES, - EM28XX_AC97, +enum em28xx_ac97_mode { + EM28XX_NO_AC97 = 0, + EM28XX_AC97_EM202, + EM28XX_AC97_OTHER, +}; + +struct em28xx_audio_mode { + enum em28xx_ac97_mode ac97; + + u16 ac97_feat; + u16 ac97_vendor_id1; + u16 ac97_vendor_id2; + + unsigned int has_audio:1; + + unsigned int i2s_3rates:1; + unsigned int i2s_5rates:1; }; enum em28xx_amux { EM28XX_AMUX_VIDEO, EM28XX_AMUX_LINE_IN, - EM28XX_AMUX_AC97_VIDEO, - EM28XX_AMUX_AC97_LINE_IN, }; struct em28xx_input { @@ -419,7 +429,7 @@ struct em28xx { u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; - enum em28xx_audio_mode audio_mode; + struct em28xx_audio_mode audio_mode; int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ @@ -544,6 +554,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_audio_analog_set(struct em28xx *dev); +int em28xx_audio_setup(struct em28xx *dev); int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); -- cgit v1.2.3 From 636008228786f51a4b2aec945cd47f1e12c60ea4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 09:56:19 -0200 Subject: em28xx: merge AC97 vendor id's into a single var From: Mauro Carvalho Chehab This makes easier to identify vendor ID, since AC97 vendors are generally identified by 3 bytes. The remaining byte is used by the vendor to identify its devices. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 11 +++++++---- linux/drivers/media/video/em28xx/em28xx.h | 3 +-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 3a6252a8b..f2f3f7900 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -424,6 +424,7 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); int em28xx_audio_setup(struct em28xx *dev) { int vid1, vid2, feat, cfg; + u32 vid; if (dev->chip_id == CHIP_ID_EM2874) { /* Digital only device - don't load any alsa module */ @@ -475,9 +476,10 @@ int em28xx_audio_setup(struct em28xx *dev) if (vid2 < 0) goto init_audio; - dev->audio_mode.ac97_vendor_id1 = vid1; - dev->audio_mode.ac97_vendor_id2 = vid2; - em28xx_warn("AC97 vendor ID = %04x:%04x\n", vid1, vid2); + vid = vid1 << 16 | vid2; + + dev->audio_mode.ac97_vendor_id = vid; + em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); feat = em28xx_read_ac97(dev, AC97_RESET); if (feat < 0) @@ -486,7 +488,8 @@ int em28xx_audio_setup(struct em28xx *dev) dev->audio_mode.ac97_feat = feat; em28xx_warn("AC97 features = 0x%04x\n", feat); - if ((vid1 == 0xffff) && (vid2 == 0xffff) && (feat == 0x6a90)) + /* Try to identify what audio processor we have */ + if ((vid == 0xffffffff) && (feat == 0x6a90)) dev->audio_mode.ac97 = EM28XX_AC97_EM202; init_audio: diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 06d5872f1..c3c36d691 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -267,8 +267,7 @@ struct em28xx_audio_mode { enum em28xx_ac97_mode ac97; u16 ac97_feat; - u16 ac97_vendor_id1; - u16 ac97_vendor_id2; + u32 ac97_vendor_id; unsigned int has_audio:1; -- cgit v1.2.3 From 28a78dfe37a3cb9c3986be2b2d1e3e6a5fece43d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 10:06:09 -0200 Subject: em28xx: improve AC97 handling From: Mauro Carvalho Chehab AC97 devices provide several input and outputs. However, before this patch, em28xx device weren't properly allowing the usage of ac97 possible combinations. Also, several input volumes were left untouched, instead of making sure that the volumes were set on mute state. This patch improves support for ac97 devices by allowing to use any inputs, and making sure that unused inputs are set on mute state. Yet, some work is still needed to select the AC97 output. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 73 +++++++++++++++----------- linux/drivers/media/video/em28xx/em28xx-reg.h | 14 ++++- linux/drivers/media/video/em28xx/em28xx.h | 20 ++++++- 3 files changed, 74 insertions(+), 33 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index f2f3f7900..5292ca29d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -298,29 +298,44 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) return 0; } -static int set_ac97_em202_input(struct em28xx *dev) +struct em28xx_input_table { + enum em28xx_amux amux; + u8 reg; +}; + +static struct em28xx_input_table inputs[] = { + { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, + { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, + { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, + { EM28XX_AMUX_MIC, AC97_MIC_VOL }, + { EM28XX_AMUX_CD, AC97_CD_VOL }, + { EM28XX_AMUX_AUX, AC97_AUX_VOL }, + { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL }, +}; + +static int set_ac97_input(struct em28xx *dev) { - int ret; - u16 enable = 0x0808; /* 12 dB attenuation Left/Right */ - u16 disable = 0x8808; /* bit 15 - mute volumme */ - u16 video, line; - - if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) { - video = enable; - line = disable; - } else { - video = disable; - line = enable; - } + int ret, i; + enum em28xx_amux amux = dev->ctl_ainput; - /* Sets em202 AC97 mixer registers */ - ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); - if (ret < 0) - return ret; + /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that + em28xx should point to LINE IN, while AC97 should use VIDEO + */ + if (amux == EM28XX_AMUX_VIDEO2) + amux = dev->ctl_ainput; - ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); + /* Mute all entres but the one that were selected */ + for (i = 0; i < ARRAY_SIZE(inputs); i++) { + if (amux == inputs[i].amux) + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808); + else + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); - return ret; + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + inputs[i].reg); + } + return 0; } static int em28xx_set_audio_source(struct em28xx *dev) @@ -329,10 +344,10 @@ static int em28xx_set_audio_source(struct em28xx *dev) u8 input; if (dev->is_em2800) { - if (dev->ctl_ainput) - input = EM2800_AUDIO_SRC_LINE; - else + if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) input = EM2800_AUDIO_SRC_TUNER; + else + input = EM2800_AUDIO_SRC_LINE; ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); if (ret < 0) @@ -360,16 +375,11 @@ static int em28xx_set_audio_source(struct em28xx *dev) switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: break; - case EM28XX_AC97_OTHER: - /* We don't know how to handle this chip. - Let's hope it is close enough to em202 to work - */ - case EM28XX_AC97_EM202: - ret = set_ac97_em202_input(dev); - break; + default: + ret = set_ac97_input(dev); } - return 0; + return ret; } int em28xx_audio_analog_set(struct em28xx *dev) @@ -380,6 +390,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (!dev->audio_mode.has_audio) return 0; + /* It is assumed that all devices use master volume for output. + It would be possible to use also line output. + */ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { /* Mute */ ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000); diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index 12c9132b0..9727f3828 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -130,10 +130,13 @@ enum em28xx_chip_id { /* Standard AC97 registers */ #define AC97_RESET 0x00 + + /* Output volumes */ #define AC97_MASTER_VOL 0x02 -#define AC97_LINE_LEVEL_VOL 0x04 +#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */ #define AC97_MASTER_MONO_VOL 0x06 + /* Input volumes */ #define AC97_PC_BEEP_VOL 0x0a #define AC97_PHONE_VOL 0x0c #define AC97_MIC_VOL 0x0e @@ -142,8 +145,12 @@ enum em28xx_chip_id { #define AC97_VIDEO_VOL 0x14 #define AC97_AUX_VOL 0x16 #define AC97_PCM_OUT_VOL 0x18 + + /* capture registers */ #define AC97_RECORD_SELECT 0x1a #define AC97_RECORD_GAIN 0x1c + + /* control registers */ #define AC97_GENERAL_PURPOSE 0x20 #define AC97_3D_CTRL 0x22 #define AC97_AUD_INT_AND_PAG 0x24 @@ -158,10 +165,15 @@ enum em28xx_chip_id { #define AC97_PCM_OUT_SURR_SRATE 0x2e #define AC97_PCM_OUT_LFE_SRATE 0x30 #define AC97_PCM_IN_SRATE 0x32 + + /* For devices with more than 2 channels, extra output volumes */ #define AC97_LFE_MASTER_VOL 0x36 #define AC97_SURR_MASTER_VOL 0x38 + + /* Digital SPDIF output control */ #define AC97_SPDIF_OUT_CTRL 0x3a + /* Vendor ID identifier */ #define AC97_VENDOR_ID1 0x7c #define AC97_VENDOR_ID2 0x7e diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index c3c36d691..fae80c42d 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -275,9 +275,25 @@ struct em28xx_audio_mode { unsigned int i2s_5rates:1; }; +/* em28xx has two audio inputs: tuner and line in. + However, on most devices, an auxiliary AC97 codec device is used. + The AC97 device may have several different inputs and outputs, + depending on their model. So, it is possible to use AC97 mixer to + address more than two different entries. + */ enum em28xx_amux { - EM28XX_AMUX_VIDEO, - EM28XX_AMUX_LINE_IN, + /* This is the only entry for em28xx tuner input */ + EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ + + EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ + + /* Some less-common mixer setups */ + EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ + EM28XX_AMUX_PHONE, + EM28XX_AMUX_MIC, + EM28XX_AMUX_CD, + EM28XX_AMUX_AUX, + EM28XX_AMUX_PCM_OUT, }; struct em28xx_input { -- cgit v1.2.3 From 0f71f2e1c83c02abd71844758e0d739b56bf4a2c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 10:52:20 -0200 Subject: Introduce a new function that writes to a single register. This is From: Devin Heitmueller useful because the vast majority of register writes are a single register, and this format permits or'ing register value bits together. Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 6 ++++++ linux/drivers/media/video/em28xx/em28xx.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 5292ca29d..dacb6cc5a 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -196,6 +196,12 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) return rc; } +/* Write a single register */ +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) +{ + return em28xx_write_regs(dev, reg, &val, 1); +} + /* * em28xx_write_reg_bits() * sets only some bits (specified by bitmask) of a register, by first reading diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index fae80c42d..9f96128df 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -568,6 +568,8 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg); int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); + int em28xx_audio_analog_set(struct em28xx *dev); int em28xx_audio_setup(struct em28xx *dev); -- cgit v1.2.3 From c6f9ed52d0eb5d04c1c65914976d81315a872839 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 10:53:05 -0200 Subject: Convert the calls that write the i2c clock register over to the new From: Devin Heitmueller em28xx_write_reg() function that allows for or'ing bits Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 60 ++++++++++++++++++------- linux/drivers/media/video/em28xx/em28xx-reg.h | 13 ++++++ 2 files changed, 58 insertions(+), 15 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 01765c33f..d2967c434 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -1405,7 +1405,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1417,7 +1419,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2882_BOARD_TERRATEC_HYBRID_XS: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* should be added ir_codes here */ @@ -1437,7 +1441,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_KWORLD_350U: case EM2881_BOARD_DNT_DA2_HYBRID: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital @@ -1454,7 +1460,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_MSI_DIGIVOX_AD: case EM2880_BOARD_MSI_DIGIVOX_AD_II: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1471,7 +1479,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_PLEXTOR_PX_TV100U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* FIXME guess */ /* Turn on analog audio output */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); @@ -1480,7 +1490,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(10); em28xx_write_regs(dev, 0x08, "\x6d", 1); msleep(10); @@ -1490,7 +1502,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_KWORLD_355U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1499,7 +1513,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_COMPRO_VIDEOMATE: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* TODO: someone can do some cleanup here... not everything's needed */ em28xx_write_regs(dev, 0x04, "\x00", 1); @@ -1518,7 +1534,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_TERRATEC_XS_MT2060: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* this device needs some gpio writes to get the DVB-T demod work */ em28xx_write_regs(dev, 0x08, "\xfe", 1); @@ -1530,7 +1548,10 @@ void em28xx_pre_card_setup(struct em28xx *dev) break; case EM2870_BOARD_PINNACLE_PCTV_DVB: - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); + /* this device needs some gpio writes to get the DVB-T demod work */ em28xx_write_regs(dev, 0x08, "\xfe", 1); @@ -1546,7 +1567,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2820_BOARD_GADMEI_UTV310: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* Turn on analog audio output */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; @@ -1554,20 +1577,27 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2860_BOARD_GADMEI_UTV330: /* Turn on IR */ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* should be added ir_codes here */ break; case EM2820_BOARD_MSI_VOX_USB_2: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* enables audio for that device */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; case EM2874_BOARD_PINNACLE_PCTV_80E: - /* Set 400 KHz clock */ - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x45", 1); + /* Set 400 KHz clock and select secondary i2c bus */ + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_FREQ_400_KHZ); dev->digital_gpio = em2874_pinnacle_80e_digital; break; diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index 9727f3828..98e95054e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -32,6 +32,19 @@ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ #define EM28XX_R06_I2C_CLK 0x06 + +/* em28xx I2C Clock Register (0x06) */ +#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80 +#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40 +#define EM28XX_I2C_EEPROM_ON_BOARD 0x08 +#define EM28XX_I2C_EEPROM_KEY_VALID 0x04 +#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */ +#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */ +#define EM28XX_I2C_FREQ_25_KHZ 0x02 +#define EM28XX_I2C_FREQ_400_KHZ 0x01 +#define EM28XX_I2C_FREQ_100_KHZ 0x00 + + #define EM28XX_R0A_CHIPID 0x0a #define EM28XX_R0C_USBSUSP 0x0c /* */ -- cgit v1.2.3 From 9881db1cdfab70b538cdd0ad234dcafbf867b62d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Nov 2008 01:03:00 +0000 Subject: Fixed typo in sizeof() causing NULL pointer OOPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Oldrich Jedlicka Signed-off-by: Oldřich Jedlička Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/saa7134/saa7134-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 65d3909d4..d4c432cb3 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -6151,7 +6151,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) struct v4l2_priv_tun_config xc2028_cfg; struct xc2028_ctrl ctl; - memset(&xc2028_cfg, 0, sizeof(ctl)); + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); memset(&ctl, 0, sizeof(ctl)); ctl.fname = XC2028_DEFAULT_FIRMWARE; -- cgit v1.2.3 From 85c98bb35cedc8a0d7ca7dc03ac20dfedab23922 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 11:30:26 -0200 Subject: em28xx: fix a race condition with hald From: Mauro Carvalho Chehab Newer versions of hald tries to open it to call QUERYCAP. Due to the lack of a proper locking, it is possible to open the device before it finishes initialization. This patch adds a lock to avoid this risk, and to protect the list of em28xx devices. While here, remove the uneeded BKL lock. Priority: high Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-video.c | 129 ++++++++++++++---------- 1 file changed, 76 insertions(+), 53 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 88bff6bd7..8cef89ad8 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -73,6 +73,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static LIST_HEAD(em28xx_devlist); +static DEFINE_MUTEX(em28xx_devlist_mutex); static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; @@ -1562,7 +1563,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) struct em28xx_fh *fh; enum v4l2_buf_type fh_type = 0; - lock_kernel(); + mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; @@ -1578,10 +1579,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev = h; } } - if (NULL == dev) { - unlock_kernel(); + mutex_unlock(&em28xx_devlist_mutex); + if (NULL == dev) return -ENODEV; - } + + mutex_lock(&dev->lock); em28xx_videodbg("open minor=%d type=%s users=%d\n", minor, v4l2_type_names[fh_type], dev->users); @@ -1590,6 +1592,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE); if (errCode < 0) { em28xx_errdev("Device locked on digital mode. Can't open analog\n"); + mutex_unlock(&dev->lock); return -EBUSY; } #endif @@ -1597,10 +1600,9 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - unlock_kernel(); + mutex_unlock(&dev->lock); return -ENOMEM; } - mutex_lock(&dev->lock); fh->dev = dev; fh->radio = radio; fh->type = fh_type; @@ -1641,7 +1643,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); - unlock_kernel(); return errCode; } @@ -1939,6 +1940,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) { struct em28xx *dev = NULL; + mutex_lock(&em28xx_devlist_mutex); mutex_lock(&em28xx_extension_devlist_lock); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { @@ -1947,6 +1949,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) } printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1955,6 +1958,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) { struct em28xx *dev = NULL; + mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { if (dev) ops->fini(dev); @@ -1964,6 +1968,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); } EXPORT_SYMBOL(em28xx_unregister_extension); @@ -1988,6 +1993,60 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } +static int register_analog_devices(struct em28xx *dev) +{ + int ret; + + /* allocate and fill video video_device struct */ + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); + if (!dev->vdev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + + /* register v4l2 video video_device */ + ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (ret) { + em28xx_errdev("unable to register video device (error=%i).\n", + ret); + return ret; + } + + /* Allocate and fill vbi video_device struct */ + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); + + /* register v4l2 vbi video_device */ + ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("unable to register vbi device\n"); + return ret; + } + + if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); + if (!dev->radio_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("can't register radio device\n"); + return ret; + } + em28xx_info("Registered radio device as /dev/radio%d\n", + dev->radio_dev->num); + } + + em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", + dev->vdev->num, dev->vbi_dev->num); + + return 0; +} + + /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -2066,50 +2125,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return errCode; } - list_add_tail(&dev->devlist, &em28xx_devlist); - - /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (NULL == dev->vdev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - - /* register v4l2 video video_device */ - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (retval) { - em28xx_errdev("unable to register video device (error=%i).\n", - retval); - goto fail_unreg; - } - - /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); - /* register v4l2 vbi video_device */ - if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]) < 0) { - em28xx_errdev("unable to register vbi device\n"); - retval = -ENODEV; - goto fail_unreg; - } - - if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); - if (NULL == dev->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (retval < 0) { - em28xx_errdev("can't register radio device\n"); - goto fail_unreg; - } - em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->num); - } - /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.queued); @@ -2139,8 +2154,14 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, video_mux(dev, 0); - em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", - dev->vdev->num, dev->vbi_dev->num); + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&dev->devlist, &em28xx_devlist); + retval = register_analog_devices(dev); + if (retval < 0) { + em28xx_release_resources(dev); + mutex_unlock(&em28xx_devlist_mutex); + goto fail_reg_devices; + } mutex_lock(&em28xx_extension_devlist_lock); if (!list_empty(&em28xx_extension_devlist)) { @@ -2150,11 +2171,13 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } } mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); return 0; fail_unreg: em28xx_release_resources(dev); +fail_reg_devices: mutex_unlock(&dev->lock); return retval; } -- cgit v1.2.3 From 6247d126d87bc803082fe3023f08c4704e430537 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 13:10:44 -0200 Subject: em28xx: Fix a stupid cut-and-paste error From: Mauro Carvalho Chehab Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index dacb6cc5a..f3e3acefb 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -328,7 +328,7 @@ static int set_ac97_input(struct em28xx *dev) em28xx should point to LINE IN, while AC97 should use VIDEO */ if (amux == EM28XX_AMUX_VIDEO2) - amux = dev->ctl_ainput; + amux = EM28XX_AMUX_VIDEO; /* Mute all entres but the one that were selected */ for (i = 0; i < ARRAY_SIZE(inputs); i++) { -- cgit v1.2.3 From 0ca43157210b3c9c92e6dbaa545f69f4e1ebbc9e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 13:40:51 -0200 Subject: em28xx: allow specifying audio output From: Mauro Carvalho Chehab Some boards use different AC97 setups for output. This patch adds the capability of specifying the output to be used. Currently, only one output is selected, but the better is to allow user to select it via a mixer, on alsa driver. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 24 ++++++++++---- linux/drivers/media/video/em28xx/em28xx-video.c | 44 +++++++++++++++++++------ linux/drivers/media/video/em28xx/em28xx.h | 10 ++++++ 3 files changed, 61 insertions(+), 17 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index f3e3acefb..bc40f2e33 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -388,9 +388,17 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } +static int outputs[] = { + [EM28XX_AOUT_MASTER] = AC97_MASTER_VOL, + [EM28XX_AOUT_LINE] = AC97_LINE_LEVEL_VOL, + [EM28XX_AOUT_MONO] = AC97_MASTER_MONO_VOL, + [EM28XX_AOUT_LFE] = AC97_LFE_MASTER_VOL, + [EM28XX_AOUT_SURR] = AC97_SURR_MASTER_VOL, +}; + int em28xx_audio_analog_set(struct em28xx *dev) { - int ret; + int ret, i; u8 xclk = 0x07; if (!dev->audio_mode.has_audio) @@ -400,11 +408,13 @@ int em28xx_audio_analog_set(struct em28xx *dev) It would be possible to use also line output. */ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - /* Mute */ - ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000); - - if (ret < 0) - return ret; + /* Mute all outputs */ + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + ret = em28xx_write_ac97(dev, outputs[i], 0x8000); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i]); + } } if (dev->has_12mhz_i2s) @@ -433,7 +443,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) vol |= 0x8000; /* Sets volume */ - ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, vol); + ret = em28xx_write_ac97(dev, outputs[dev->ctl_aoutput], vol); } return ret; diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 8cef89ad8..70a43e13e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -571,6 +571,7 @@ static void video_mux(struct em28xx *dev, int index) route.output = 0; dev->ctl_input = index; dev->ctl_ainput = INPUT(index)->amux; + dev->ctl_aoutput = INPUT(index)->aout; em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); @@ -933,20 +934,38 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - unsigned int index = a->index; - if (a->index > 1) - return -EINVAL; - - index = dev->ctl_ainput; - - if (index == 0) + switch (a->index) { + case EM28XX_AMUX_VIDEO: strcpy(a->name, "Television"); - else + break; + case EM28XX_AMUX_LINE_IN: strcpy(a->name, "Line In"); + break; + case EM28XX_AMUX_VIDEO2: + strcpy(a->name, "Television alt"); + break; + case EM28XX_AMUX_PHONE: + strcpy(a->name, "Phone"); + break; + case EM28XX_AMUX_MIC: + strcpy(a->name, "Mic"); + break; + case EM28XX_AMUX_CD: + strcpy(a->name, "CD"); + break; + case EM28XX_AMUX_AUX: + strcpy(a->name, "Aux"); + break; + case EM28XX_AMUX_PCM_OUT: + strcpy(a->name, "PCM"); + break; + default: + return -EINVAL; + } + a->index = dev->ctl_ainput; a->capability = V4L2_AUDCAP_STEREO; - a->index = index; return 0; } @@ -956,9 +975,14 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; +#if 0 + /* Doesn't allow manual routing */ if (a->index != dev->ctl_ainput) return -EINVAL; - +#else + dev->ctl_ainput = INPUT(a->index)->amux; + dev->ctl_aoutput = INPUT(a->index)->aout; +#endif return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 9f96128df..2d74b5c5c 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -296,10 +296,19 @@ enum em28xx_amux { EM28XX_AMUX_PCM_OUT, }; +enum em28xx_aout { + EM28XX_AOUT_MASTER = 0, /* should be the default */ + EM28XX_AOUT_LINE, + EM28XX_AOUT_MONO, + EM28XX_AOUT_LFE, + EM28XX_AOUT_SURR, +}; + struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; enum em28xx_amux amux; + enum em28xx_aout aout; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -459,6 +468,7 @@ struct em28xx { int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput;/* selected audio input */ + unsigned int ctl_aoutput;/* selected audio output */ int mute; int volume; /* frame properties */ -- cgit v1.2.3 From 9c67fb052ee5c718868e6b9b422cdaf4e001dec4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 13:49:33 -0200 Subject: em28xx: Add detection of Sigmatel Stac97xx series of AC97 devices From: Mauro Carvalho Chehab Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 6 ++++++ linux/drivers/media/video/em28xx/em28xx.h | 1 + 2 files changed, 7 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index bc40f2e33..711584515 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -520,6 +520,8 @@ int em28xx_audio_setup(struct em28xx *dev) /* Try to identify what audio processor we have */ if ((vid == 0xffffffff) && (feat == 0x6a90)) dev->audio_mode.ac97 = EM28XX_AC97_EM202; + else if ((vid >> 8) == 0x838476) + dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; init_audio: /* Reports detected AC97 processor */ @@ -530,6 +532,10 @@ init_audio: case EM28XX_AC97_EM202: em28xx_info("Empia 202 AC97 audio processor detected\n"); break; + case EM28XX_AC97_SIGMATEL: + em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n", + dev->audio_mode.ac97_vendor_id & 0xff); + break; case EM28XX_AC97_OTHER: em28xx_warn("Unknown AC97 audio processor detected!\n"); break; diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 2d74b5c5c..7de9afb0e 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -260,6 +260,7 @@ enum enum28xx_itype { enum em28xx_ac97_mode { EM28XX_NO_AC97 = 0, EM28XX_AC97_EM202, + EM28XX_AC97_SIGMATEL, EM28XX_AC97_OTHER, }; -- cgit v1.2.3 From 28e0ca25a6ca00f5568a1e5dcb884ab090595bc0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 14:39:39 -0200 Subject: Allow opening more than one output at the same time From: Mauro Carvalho Chehab Some devices use more than one AC97 outputs. This patch allows such devices to properly work. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-core.c | 33 +++++++++++++++---------- linux/drivers/media/video/em28xx/em28xx-video.c | 6 +++++ linux/drivers/media/video/em28xx/em28xx.h | 10 ++++---- 3 files changed, 31 insertions(+), 18 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 711584515..eb8515895 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -304,12 +304,12 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) return 0; } -struct em28xx_input_table { - enum em28xx_amux amux; +struct em28xx_vol_table { + enum em28xx_amux mux; u8 reg; }; -static struct em28xx_input_table inputs[] = { +static struct em28xx_vol_table inputs[] = { { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, @@ -332,7 +332,7 @@ static int set_ac97_input(struct em28xx *dev) /* Mute all entres but the one that were selected */ for (i = 0; i < ARRAY_SIZE(inputs); i++) { - if (amux == inputs[i].amux) + if (amux == inputs[i].mux) ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808); else ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); @@ -388,12 +388,12 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } -static int outputs[] = { - [EM28XX_AOUT_MASTER] = AC97_MASTER_VOL, - [EM28XX_AOUT_LINE] = AC97_LINE_LEVEL_VOL, - [EM28XX_AOUT_MONO] = AC97_MASTER_MONO_VOL, - [EM28XX_AOUT_LFE] = AC97_LFE_MASTER_VOL, - [EM28XX_AOUT_SURR] = AC97_SURR_MASTER_VOL, +struct em28xx_vol_table outputs[] = { + { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, + { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, + { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, + { EM28XX_AOUT_LFE, AC97_LFE_MASTER_VOL }, + { EM28XX_AOUT_SURR, AC97_SURR_MASTER_VOL }, }; int em28xx_audio_analog_set(struct em28xx *dev) @@ -410,10 +410,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { /* Mute all outputs */ for (i = 0; i < ARRAY_SIZE(outputs); i++) { - ret = em28xx_write_ac97(dev, outputs[i], 0x8000); + ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); if (ret < 0) em28xx_warn("couldn't setup AC97 register %d\n", - outputs[i]); + outputs[i].reg); } } @@ -443,7 +443,14 @@ int em28xx_audio_analog_set(struct em28xx *dev) vol |= 0x8000; /* Sets volume */ - ret = em28xx_write_ac97(dev, outputs[dev->ctl_aoutput], vol); + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + if (dev->ctl_aoutput & outputs[i].mux) + ret = em28xx_write_ac97(dev, outputs[i].reg, + vol); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i].reg); + } } return ret; diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 70a43e13e..e585780c8 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -573,6 +573,9 @@ static void video_mux(struct em28xx *dev, int index) dev->ctl_ainput = INPUT(index)->amux; dev->ctl_aoutput = INPUT(index)->aout; + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; + em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); if (dev->has_msp34xx) { @@ -982,6 +985,9 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) #else dev->ctl_ainput = INPUT(a->index)->amux; dev->ctl_aoutput = INPUT(a->index)->aout; + + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; #endif return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 7de9afb0e..151668c60 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -298,11 +298,11 @@ enum em28xx_amux { }; enum em28xx_aout { - EM28XX_AOUT_MASTER = 0, /* should be the default */ - EM28XX_AOUT_LINE, - EM28XX_AOUT_MONO, - EM28XX_AOUT_LFE, - EM28XX_AOUT_SURR, + EM28XX_AOUT_MASTER = 1 << 0, + EM28XX_AOUT_LINE = 1 << 1, + EM28XX_AOUT_MONO = 1 << 2, + EM28XX_AOUT_LFE = 1 << 3, + EM28XX_AOUT_SURR = 1 << 4, }; struct em28xx_input { -- cgit v1.2.3 From 5b08829d068b1cfdf62e0920618a5290101c3d45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 14:43:05 -0200 Subject: em28xx: fix Pixelview PlayTV board entry From: Mauro Carvalho Chehab Pixelview uses a Sigmatel stac codec. It has an external line out pin, connected to AC97_MASTER_VOL. It also provides I2S output, but using a different volume for this (AC97_MONO_VOL). Now that AC97 setup is finally fixed, such boards will work better. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index d2967c434..1a1dd2085 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -848,7 +848,9 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, + .amux = EM28XX_AMUX_VIDEO, + .aout = EM28XX_AOUT_MONO | /* I2S */ + EM28XX_AOUT_MASTER, /* Line out pin */ }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, -- cgit v1.2.3 From cf4b37dddc28c17056179e3b7ecb15660952db7e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 19:38:29 -0200 Subject: em28xx: devices with xc2028/3028 don't have tda9887 From: Mauro Carvalho Chehab This patch cleans up the entries of xc2028/3028, since those devices don't need or use a tda9887. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 1a1dd2085..a9ae6ea6e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -588,7 +588,6 @@ struct em28xx_board em28xx_boards[] = { [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, @@ -612,7 +611,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { .name = "Pinnacle PCTV HD Pro Stick", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, @@ -636,7 +634,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { .name = "AMD ATI TV Wonder HD 600", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, @@ -660,7 +657,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .has_dvb = 1, @@ -684,7 +680,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .input = { { -- cgit v1.2.3 From 629cb47b4af820e76773eac137150742487afbfb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Nov 2008 19:47:37 -0200 Subject: em28xx: fix a regression caused by changeset 9630 From: Mauro Carvalho Chehab If removing and reiserting the driver on some devices, tuner type will be unset at the second time. This patch fixes this issue. Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index a9ae6ea6e..9177ea54b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -1806,7 +1806,8 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); dev->tuner_type = em28xx_boards[dev->model].tuner_type; - dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; + if (em28xx_boards[dev->model].tuner_addr) + dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; /* request some modules */ switch (dev->model) { -- cgit v1.2.3 From 520e23e06771404dd24313d5debf22dca73746ba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 21 Nov 2008 20:00:55 -0200 Subject: bttv: fix some entries on Phytec boards and add missing ones From: Dirk Heer This Patch does modify the bttv-cards.c and bttc.h so that the driver supports VD-011, VD-012, VD-012-X1 and VD-012-X2 Framegrabber from Phytec Messtechnik GmbH. Priority: normal Signed-off-by: Dirk Heer Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/bt8xx/bttv-cards.c | 60 +++++++++++++++++++++++++--- linux/drivers/media/video/bt8xx/bttv.h | 8 +++- 2 files changed, 60 insertions(+), 8 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index d67e127f1..a00228893 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -2240,9 +2240,9 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, - [BTTV_BOARD_VD009X1_MINIDIN] = { + [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { /* M.Klahr@phytec.de */ - .name = "PHYTEC VD-009-X1 MiniDIN (bt878)", + .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", .video_inputs = 4, .audio_inputs = 0, .tuner = UNSET, /* card has no tuner */ @@ -2250,14 +2250,14 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .muxsel = { 2, 3, 1, 0 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, + .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, - [BTTV_BOARD_VD009X1_COMBI] = { - .name = "PHYTEC VD-009-X1 Combi (bt878)", + [BTTV_BOARD_VD009X1_VD011_COMBI] = { + .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", .video_inputs = 4, .audio_inputs = 0, .tuner = UNSET, /* card has no tuner */ @@ -2265,7 +2265,7 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, + .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -3093,6 +3093,54 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .has_radio = 1, .has_remote = 1, + }, + [BTTV_BOARD_VD012] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = UNSET, /* card has no s-video */ + .gpiomask = 0x00, + .muxsel = { 0, 2, 3, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X1] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X1 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = { 2, 3, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X2] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X2 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = { 3, 2, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, } }; diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h index 20f027ee4..ed0446a20 100644 --- a/linux/drivers/media/video/bt8xx/bttv.h +++ b/linux/drivers/media/video/bt8xx/bttv.h @@ -131,8 +131,8 @@ #define BTTV_BOARD_XGUARD 0x67 #define BTTV_BOARD_NEBULA_DIGITV 0x68 #define BTTV_BOARD_PV143 0x69 -#define BTTV_BOARD_VD009X1_MINIDIN 0x6a -#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b #define BTTV_BOARD_VD009_MINIDIN 0x6c #define BTTV_BOARD_VD009_COMBI 0x6d #define BTTV_BOARD_IVC100 0x6e @@ -178,6 +178,10 @@ #define BTTV_BOARD_GEOVISION_GV600 0x96 #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 #define BTTV_BOARD_ENLTV_FM_2 0x98 +#define BTTV_BOARD_VD012 0x99 +#define BTTV_BOARD_VD012_X1 0x9a +#define BTTV_BOARD_VD012_X2 0x9b + /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 -- cgit v1.2.3