提交 4ef4327b 编写于 作者: L Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (120 commits)
  cx231xx: Convert to snd_card_create()
  V4L/DVB (11440): PWC: fix build error when CONFIG_INPUT=m
  V4L/DVB (11439): UVC: uvc_status_cleanup(): undefined reference to `input_unregister_device'
  V4L/DVB (11438): au0828: fix Kconfig dependance
  V4L/DVB (11437): pvrusb2: Drop client_register/unregister stubs
  V4L/DVB (11436): radio-mr800: convert to to v4l2_device
  V4L/DVB (11435): dsbr100 radio: convert to to v4l2_device
  V4L/DVB: zr364xx: remove unused #include <version.h>
  V4L/DVB: usbvision: remove unused #include <version.h>
  V4L/DVB (11427): gspca - m5602: Minor cleanups
  V4L/DVB (11426): gspca - m5602: Don't touch hflip/vflip register on Read/Modify/Write
  V4L/DVB (11425): gspca - m5602: Move the vflip quirk to probe stage.
  V4L/DVB (11424): gspca - m5602-ov9650: Use the local ctrl cache. Adjust image on vflip.
  V4L/DVB (11423): gspca - m5602-ov9650: Add a disconnect hook, setup a ctrl cache ctrl.
  V4L/DVB (11422): gspca - m5602-ov9650: Replace a magic constant with a define
  V4L/DVB (11421): gspca - m5602-ov9650: Synthesize modesetting.
  V4L/DVB (11420): gspca - m5602: Improve error handling in the ov9650 driver
  V4L/DVB (11419): gspca - m5602-ov9650: Don't read exposure data from COM1.
  V4L/DVB (11418): gspca - m5602-ov9650: Auto white balancing is on by default
  V4L/DVB (11417): gspca - m5602-ov9650: Autogain is on by default
  ...
PXA-Camera Host Driver
======================
Constraints
-----------
a) Image size for YUV422P format
All YUV422P images are enforced to have width x height % 16 = 0.
This is due to DMA constraints, which transfers only planes of 8 byte
multiples.
Global video workflow
---------------------
a) QCI stopped
Initialy, the QCI interface is stopped.
When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts.
b) QCI started
More buffers can be queued while the QCI is started without halting the
capture. The new buffers are "appended" at the tail of the DMA chain, and
smoothly captured one frame after the other.
Once a buffer is filled in the QCI interface, it is marked as "DONE" and
removed from the active buffers list. It can be then requeud or dequeued by
userland application.
Once the last buffer is filled in, the QCI interface stops.
DMA usage
---------
a) DMA flow
- first buffer queued for capture
Once a first buffer is queued for capture, the QCI is started, but data
transfer is not started. On "End Of Frame" interrupt, the irq handler
starts the DMA chain.
- capture of one videobuffer
The DMA chain starts transfering data into videobuffer RAM pages.
When all pages are transfered, the DMA irq is raised on "ENDINTR" status
- finishing one videobuffer
The DMA irq handler marks the videobuffer as "done", and removes it from
the active running queue
Meanwhile, the next videobuffer (if there is one), is transfered by DMA
- finishing the last videobuffer
On the DMA irq of the last videobuffer, the QCI is stopped.
b) DMA prepared buffer will have this structure
+------------+-----+---------------+-----------------+
| desc-sg[0] | ... | desc-sg[last] | finisher/linker |
+------------+-----+---------------+-----------------+
This structure is pointed by dma->sg_cpu.
The descriptors are used as follows :
- desc-sg[i]: i-th descriptor, transfering the i-th sg
element to the video buffer scatter gather
- finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
- linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0
For the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N],
"f" stands for finisher and "l" for linker.
A typical running chain is :
Videobuffer 1 Videobuffer 2
+---------+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+---+
| |
+----+
After the chaining is finished, the chain looks like :
Videobuffer 1 Videobuffer 2 Videobuffer 3
+---------+----+---+ +----+----+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
| | | |
+----+ +----+
new_link
c) DMA hot chaining timeslice issue
As DMA chaining is done while DMA _is_ running, the linking may be done
while the DMA jumps from one Videobuffer to another. On the schema, that
would be a problem if the following sequence is encountered :
- DMA chain is Videobuffer1 + Videobuffer2
- pxa_videobuf_queue() is called to queue Videobuffer3
- DMA controller finishes Videobuffer2, and DMA stops
=>
Videobuffer 1 Videobuffer 2
+---------+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-^-+
| | |
+----+ +-- DMA DDADR loads DDADR_STOP
- pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is
replaced by a "linker" to Videobuffer3 (creation of new_link)
- pxa_videobuf_queue() finishes
- the DMA irq handler is called, which terminates Videobuffer2
- Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!)
Videobuffer 1 Videobuffer 2 Videobuffer 3
+---------+----+---+ +----+----+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
| | | |
+----+ +----+
new_link
DMA DDADR still is DDADR_STOP
- pxa_camera_check_link_miss() is called
This checks if the DMA is finished and a buffer is still on the
pcdev->capture list. If that's the case, the capture will be restarted,
and Videobuffer3 is scheduled on DMA chain.
- the DMA irq handler finishes
Note: if DMA stops just after pxa_camera_check_link_miss() reads DDADR()
value, we have the guarantee that the DMA irq handler will be called back
when the DMA will finish the buffer, and pxa_camera_check_link_miss() will
be called again, to reschedule Videobuffer3.
--
Author: Robert Jarzmik <robert.jarzmik@free.fr>
......@@ -90,7 +90,7 @@ up before calling v4l2_device_register then it will be untouched. If dev is
NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
The first 'dev' argument is normally the struct device pointer of a pci_dev,
usb_device or platform_device. It is rare for dev to be NULL, but it happens
usb_interface or platform_device. It is rare for dev to be NULL, but it happens
with ISA devices or when one device creates multiple PCI devices, thus making
it impossible to associate v4l2_dev with a particular parent.
......@@ -351,17 +351,6 @@ And this to go from an i2c_client to a v4l2_subdev struct:
struct v4l2_subdev *sd = i2c_get_clientdata(client);
Finally you need to make a command function to make driver->command()
call the right subdev_ops functions:
static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
If driver->command is never used then you can leave this out. Eventually the
driver->command usage should be removed from v4l.
Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
is called. This will unregister the sub-device from the bridge driver. It is
safe to call this even if the sub-device was never registered.
......@@ -375,14 +364,12 @@ from the remove() callback ensures that this is always done correctly.
The bridge driver also has some helper functions it can use:
struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36);
struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter,
"module_foo", "chipid", 0x36);
This loads the given module (can be NULL if no module needs to be loaded) and
calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
If all goes well, then it registers the subdev with the v4l2_device. It gets
the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
to call i2c_set_adapdata(adapter, v4l2_device) when you setup the i2c_adapter
in your driver.
If all goes well, then it registers the subdev with the v4l2_device.
You can also use v4l2_i2c_new_probed_subdev() which is very similar to
v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
......
......@@ -1544,7 +1544,6 @@ S: Maintained
DVB SUBSYSTEM AND DRIVERS
P: LinuxTV.org Project
M: linux-media@vger.kernel.org
L: linux-dvb@linuxtv.org (subscription required)
W: http://linuxtv.org/
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
......
......@@ -6,6 +6,9 @@
obj-y += generic.o clock.o devices.o
# Support for CMOS sensor interface
obj-$(CONFIG_MX1_VIDEO) += ksym_mx1.o mx1_camera_fiq.o
# Specific board support
obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
obj-$(CONFIG_MACH_SCB9328) += scb9328.o
\ No newline at end of file
......@@ -44,7 +44,7 @@ static struct resource imx_csi_resources[] = {
static u64 imx_csi_dmamask = 0xffffffffUL;
struct platform_device imx_csi_device = {
.name = "imx-csi",
.name = "mx1-camera",
.id = 0, /* This is used to put cameras on this interface */
.dev = {
.dma_mask = &imx_csi_dmamask,
......
/*
* Exported ksyms of ARCH_MX1
*
* Copyright (C) 2008, Darius Augulis <augulis.darius@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <mach/mx1_camera.h>
/* IMX camera FIQ handler */
EXPORT_SYMBOL(mx1_camera_sof_fiq_start);
EXPORT_SYMBOL(mx1_camera_sof_fiq_end);
/*
* Copyright (C) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* Based on linux/arch/arm/lib/floppydma.S
* Copyright (C) 1995, 1996 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
.text
.global mx1_camera_sof_fiq_end
.global mx1_camera_sof_fiq_start
mx1_camera_sof_fiq_start:
@ enable dma
ldr r12, [r9]
orr r12, r12, #0x00000001
str r12, [r9]
@ unmask DMA interrupt
ldr r12, [r8]
bic r12, r12, r13
str r12, [r8]
@ disable SOF interrupt
ldr r12, [r10]
bic r12, r12, #0x00010000
str r12, [r10]
@ clear SOF flag
mov r12, #0x00010000
str r12, [r11]
@ return from FIQ
subs pc, lr, #4
mx1_camera_sof_fiq_end:
......@@ -533,7 +533,7 @@ static struct clk_lookup lookups[] __initdata = {
_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
_REGISTER_CLOCK("mx3-camera.0", "csi", csi_clk)
_REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
......
......@@ -24,4 +24,12 @@
#define PHYS_OFFSET UL(0x80000000)
#endif
#if defined(CONFIG_MX1_VIDEO)
/*
* Increase size of DMA-consistent memory region.
* This is required for i.MX camera driver to capture at least four VGA frames.
*/
#define CONSISTENT_DMA_SIZE SZ_4M
#endif /* CONFIG_MX1_VIDEO */
#endif /* __ASM_ARCH_MXC_MEMORY_H__ */
/*
* mx1_camera.h - i.MX1/i.MXL camera driver header file
*
* Copyright (c) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
* Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
*
* Based on PXA camera.h file:
* Copyright (C) 2003, Intel Corporation
* Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARCH_CAMERA_H_
#define __ASM_ARCH_CAMERA_H_
#define MX1_CAMERA_DATA_HIGH 1
#define MX1_CAMERA_PCLK_RISING 2
#define MX1_CAMERA_VSYNC_HIGH 4
extern unsigned char mx1_camera_sof_fiq_start, mx1_camera_sof_fiq_end;
/**
* struct mx1_camera_pdata - i.MX1/i.MXL camera platform data
* @mclk_10khz: master clock frequency in 10kHz units
* @flags: MX1 camera platform flags
*/
struct mx1_camera_pdata {
unsigned long mclk_10khz;
unsigned long flags;
};
#endif /* __ASM_ARCH_CAMERA_H_ */
......@@ -294,7 +294,7 @@ config DVB_USB_DTV5100
config DVB_USB_AF9015
tristate "Afatech AF9015 DVB-T USB2.0 support"
depends on DVB_USB && EXPERIMENTAL
depends on DVB_USB
select DVB_AF9013
select DVB_PLL if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
......@@ -309,6 +309,6 @@ config DVB_USB_CE6230
tristate "Intel CE6230 DVB-T USB2.0 support"
depends on DVB_USB && EXPERIMENTAL
select DVB_ZL10353
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
......@@ -782,17 +782,14 @@ static int af9015_read_config(struct usb_device *udev)
ARRAY_SIZE(af9015_ir_table_leadtek);
break;
case USB_VID_VISIONPLUS:
if (udev->descriptor.idProduct ==
cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
af9015_properties[i].rc_key_map =
af9015_rc_keys_twinhan;
af9015_properties[i].rc_key_map_size =
ARRAY_SIZE(af9015_rc_keys_twinhan);
af9015_config.ir_table =
af9015_ir_table_twinhan;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_twinhan);
}
af9015_properties[i].rc_key_map =
af9015_rc_keys_twinhan;
af9015_properties[i].rc_key_map_size =
ARRAY_SIZE(af9015_rc_keys_twinhan);
af9015_config.ir_table =
af9015_ir_table_twinhan;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_twinhan);
break;
case USB_VID_KWORLD_2:
/* TODO: use correct rc keys */
......@@ -833,6 +830,16 @@ static int af9015_read_config(struct usb_device *udev)
af9015_ir_table_msi;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_msi);
} else if (udev->descriptor.idProduct ==
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
af9015_properties[i].rc_key_map =
af9015_rc_keys_trekstor;
af9015_properties[i].rc_key_map_size =
ARRAY_SIZE(af9015_rc_keys_trekstor);
af9015_config.ir_table =
af9015_ir_table_trekstor;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_trekstor);
}
break;
case USB_VID_AVERMEDIA:
......@@ -981,6 +988,21 @@ static int af9015_read_config(struct usb_device *udev)
if (ret)
err("eeprom read failed:%d", ret);
/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
content :-( Override some wrong values here. */
if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
deb_info("%s: AverMedia A850: overriding config\n", __func__);
/* disable dual mode */
af9015_config.dual_mode = 0;
/* disable 2nd adapter */
for (i = 0; i < af9015_properties_count; i++)
af9015_properties[i].num_adapters = 1;
/* set correct IF */
af9015_af9013_config[0].tuner_if = 4570;
}
return ret;
}
......@@ -1237,6 +1259,9 @@ static struct usb_device_id af9015_usb_table[] = {
/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
{USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
......@@ -1401,7 +1426,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 7,
.num_device_descs = 9,
.devices = {
{
.name = "Xtensions XD-380",
......@@ -1437,7 +1462,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.name = "KWorld USB DVB-T TV Stick II " \
"(VS-DVB-T 395U)",
.cold_ids = {&af9015_usb_table[16],
&af9015_usb_table[17], NULL},
&af9015_usb_table[17],
&af9015_usb_table[18], NULL},
.warm_ids = {NULL},
},
{
.name = "TrekStor DVB-T USB Stick",
.cold_ids = {&af9015_usb_table[19], NULL},
.warm_ids = {NULL},
},
{
.name = "AverMedia AVerTV Volar Black HD " \
"(A850)",
.cold_ids = {&af9015_usb_table[20], NULL},
.warm_ids = {NULL},
},
}
......
......@@ -64,14 +64,6 @@
#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
#define AF9015_GPIO_ON (1 << 0)
#define AF9015_GPIO_EN (1 << 1)
#define AF9015_GPIO_O (1 << 2)
#define AF9015_GPIO_I (1 << 3)
#define AF9015_GPIO_TUNER_ON (AF9015_GPIO_ON|AF9015_GPIO_EN)
#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O)
struct req_t {
u8 cmd; /* [0] */
/* seq */ /* [1] */
......@@ -120,11 +112,11 @@ struct af9015_config {
enum af9015_remote {
AF9015_REMOTE_NONE = 0,
AF9015_REMOTE_A_LINK_DTU_M,
/* 1 */ AF9015_REMOTE_A_LINK_DTU_M,
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
AF9015_REMOTE_MYGICTV_U718,
AF9015_REMOTE_DIGITTRADE_DVB_T,
AF9015_REMOTE_AVERMEDIA_KS,
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
};
/* Leadtek WinFast DTV Dongle Gold */
......@@ -691,4 +683,67 @@ static u8 af9015_ir_table_digittrade[] = {
0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
};
/* TREKSTOR DVB-T USB Stick */
static struct dvb_usb_rc_key af9015_rc_keys_trekstor[] = {
{ 0x07, 0x04, KEY_AGAIN }, /* Home */
{ 0x07, 0x05, KEY_MUTE }, /* Mute */
{ 0x07, 0x06, KEY_UP }, /* Up */
{ 0x07, 0x07, KEY_DOWN }, /* Down */
{ 0x07, 0x09, KEY_RIGHT }, /* Right */
{ 0x07, 0x0a, KEY_ENTER }, /* OK */
{ 0x07, 0x0b, KEY_FASTFORWARD }, /* Fast forward */
{ 0x07, 0x0c, KEY_REWIND }, /* Rewind */
{ 0x07, 0x0d, KEY_PLAY }, /* Play/Pause */
{ 0x07, 0x0e, KEY_VOLUMEUP }, /* Volume + */
{ 0x07, 0x0f, KEY_VOLUMEDOWN }, /* Volume - */
{ 0x07, 0x10, KEY_RECORD }, /* Record */
{ 0x07, 0x11, KEY_STOP }, /* Stop */
{ 0x07, 0x12, KEY_ZOOM }, /* TV */
{ 0x07, 0x13, KEY_EPG }, /* Info/EPG */
{ 0x07, 0x14, KEY_CHANNELDOWN }, /* Channel - */
{ 0x07, 0x15, KEY_CHANNELUP }, /* Channel + */
{ 0x07, 0x1e, KEY_1 },
{ 0x07, 0x1f, KEY_2 },
{ 0x07, 0x20, KEY_3 },
{ 0x07, 0x21, KEY_4 },
{ 0x07, 0x22, KEY_5 },
{ 0x07, 0x23, KEY_6 },
{ 0x07, 0x24, KEY_7 },
{ 0x07, 0x25, KEY_8 },
{ 0x07, 0x26, KEY_9 },
{ 0x07, 0x08, KEY_LEFT }, /* LEFT */
{ 0x07, 0x27, KEY_0 },
};
static u8 af9015_ir_table_trekstor[] = {
0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
};
#endif
......@@ -250,6 +250,7 @@ static int ce6230_probe(struct usb_interface *intf,
static struct usb_device_id ce6230_table[] = {
{ USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ce6230_table);
......@@ -284,13 +285,18 @@ static struct dvb_usb_device_properties ce6230_properties = {
.i2c_algo = &ce6230_i2c_algo,
.num_device_descs = 1,
.num_device_descs = 2,
.devices = {
{
.name = "Intel CE9500 reference design",
.cold_ids = {NULL},
.warm_ids = {&ce6230_table[0], NULL},
},
{
.name = "AVerMedia A310 USB 2.0 DVB-T tuner",
.cold_ids = {NULL},
.warm_ids = {&ce6230_table[1], NULL},
},
}
};
......
......@@ -65,6 +65,7 @@
#define USB_PID_AFATECH_AF9005 0x9020
#define USB_PID_AFATECH_AF9015_9015 0x9015
#define USB_PID_AFATECH_AF9015_9016 0x9016
#define USB_PID_TREKSTOR_DVBT 0x901b
#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_ANSONIC_DVBT_USB 0x6000
#define USB_PID_ANYSEE 0x861f
......@@ -102,6 +103,7 @@
#define USB_PID_KWORLD_399U 0xe399
#define USB_PID_KWORLD_395U 0xe396
#define USB_PID_KWORLD_395U_2 0xe39b
#define USB_PID_KWORLD_395U_3 0xe395
#define USB_PID_KWORLD_PC160_2T 0xc160
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
......@@ -167,6 +169,8 @@
#define USB_PID_AVERMEDIA_VOLAR_X 0xa815
#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150
#define USB_PID_AVERMEDIA_A309 0xa309
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
......
......@@ -151,7 +151,7 @@ static void debug_fcp(const u8 *data, int length)
subunit_type = data[1] >> 3;
subunit_id = data[1] & 7;
op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
printk(KERN_INFO "%ssu=%x.%x l=%zu: %-8s - %s\n",
printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
prefix, subunit_type, subunit_id, length,
debug_fcp_ctype(data[0]),
debug_fcp_opcode(op, data, length));
......
......@@ -513,6 +513,13 @@ config DVB_LGS8GL5
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
config DVB_LGS8GXX
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
......
......@@ -61,6 +61,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
obj-$(CONFIG_DVB_AF9013) += af9013.o
obj-$(CONFIG_DVB_CX24116) += cx24116.o
......
......@@ -652,7 +652,7 @@ static int au8522_reset(struct v4l2_subdev *sd, u32 val)
}
static int au8522_s_video_routing(struct v4l2_subdev *sd,
const struct v4l2_routing *route)
u32 input, u32 output, u32 config)
{
struct au8522_state *state = to_state(sd);
......@@ -663,11 +663,11 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
closed), and then came back to analog mode */
au8522_writereg(state, 0x106, 1);
if (route->input == AU8522_COMPOSITE_CH1) {
if (input == AU8522_COMPOSITE_CH1) {
au8522_setup_cvbs_mode(state);
} else if (route->input == AU8522_SVIDEO_CH13) {
} else if (input == AU8522_SVIDEO_CH13) {
au8522_setup_svideo_mode(state);
} else if (route->input == AU8522_COMPOSITE_CH4_SIF) {
} else if (input == AU8522_COMPOSITE_CH4_SIF) {
au8522_setup_cvbs_tuner_mode(state);
} else {
printk(KERN_ERR "au8522 mode not currently supported\n");
......@@ -677,10 +677,10 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
}
static int au8522_s_audio_routing(struct v4l2_subdev *sd,
const struct v4l2_routing *route)
u32 input, u32 output, u32 config)
{
struct au8522_state *state = to_state(sd);
set_audio_input(state, route->input);
set_audio_input(state, input);
return 0;
}
......
/*
* Support for Legend Silicon DMB-TH demodulator
* LGS8913, LGS8GL5
* experimental support LGS8G42, LGS8G52
*
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "lgs8gxx.h"
#include "lgs8gxx_priv.h"
#define dprintk(args...) \
do { \
if (debug) \
printk(KERN_DEBUG "lgs8gxx: " args); \
} while (0)
static int debug;
static int fake_signal_str;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
"Signal strength calculation is slow.(default:off).");
/* LGS8GXX internal helper functions */
static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
{
int ret;
u8 buf[] = { reg, data };
struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
msg.addr = priv->config->demod_address;
if (reg >= 0xC0)
msg.addr += 0x02;
if (debug >= 2)
printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
__func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg, 1);
if (ret != 1)
dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
__func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
{
int ret;
u8 dev_addr;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{ .flags = 0, .buf = b0, .len = 1 },
{ .flags = I2C_M_RD, .buf = b1, .len = 1 },
};
dev_addr = priv->config->demod_address;
if (reg >= 0xC0)
dev_addr += 0x02;
msg[1].addr = msg[0].addr = dev_addr;
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret != 2) {
dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
__func__, reg, ret);
return -1;
}
*p_data = b1[0];
if (debug >= 2)
printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
__func__, reg, b1[0]);
return 0;
}
static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
{
lgs8gxx_write_reg(priv, 0x02, 0x00);
msleep(1);
lgs8gxx_write_reg(priv, 0x02, 0x01);
msleep(100);
return 0;
}
static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
{
const struct lgs8gxx_config *config = priv->config;
u8 if_conf;
if_conf = 0x10; /* AGC output on; */
if_conf |=
((config->ext_adc) ? 0x80 : 0x00) |
((config->if_neg_center) ? 0x04 : 0x00) |
((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) |
((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00);
if (config->ext_adc &&
(config->prod == LGS8GXX_PROD_LGS8G52)) {
lgs8gxx_write_reg(priv, 0xBA, 0x40);
}
lgs8gxx_write_reg(priv, 0x07, if_conf);
return 0;
}
static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
{
u64 val;
u32 v32;
u32 if_clk;
if_clk = priv->config->if_clk_freq;
val = freq;
if (freq != 0) {
val *= (u64)1 << 32;
if (if_clk != 0)
do_div(val, if_clk);
v32 = val & 0xFFFFFFFF;
dprintk("Set IF Freq to %dkHz\n", freq);
} else {
v32 = 0;
dprintk("Set IF Freq to baseband\n");
}
dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
return 0;
}
static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
{
u8 t;
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
lgs8gxx_write_reg(priv, 0xC6, 0x01);
lgs8gxx_read_reg(priv, 0x7E, &t);
lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
/* clear FEC self reset */
lgs8gxx_read_reg(priv, 0xC5, &t);
lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
/* FEC auto detect */
lgs8gxx_write_reg(priv, 0xC1, 0x03);
lgs8gxx_read_reg(priv, 0x7C, &t);
t = (t & 0x8C) | 0x03;
lgs8gxx_write_reg(priv, 0x7C, t);
}
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
/* BER test mode */
lgs8gxx_read_reg(priv, 0xC3, &t);
t = (t & 0xEF) | 0x10;
lgs8gxx_write_reg(priv, 0xC3, t);
}
if (priv->config->prod == LGS8GXX_PROD_LGS8G52)
lgs8gxx_write_reg(priv, 0xD9, 0x40);
return 0;
}
static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
{
int ret = 0;
u8 t;
/* turn off auto-detect; manual settings */
lgs8gxx_write_reg(priv, 0x7E, 0);
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
lgs8gxx_write_reg(priv, 0xC1, 0);
ret = lgs8gxx_read_reg(priv, 0xC5, &t);
t = (t & 0xE0) | 0x06;
lgs8gxx_write_reg(priv, 0xC5, t);
lgs8gxx_soft_reset(priv);
return 0;
}
static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
{
int ret = 0;
u8 t;
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
if (ret != 0)
return ret;
*locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
return 0;
}
static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
u8 *finished)
{
int ret = 0;
u8 t;
ret = lgs8gxx_read_reg(priv, 0xA4, &t);
if (ret != 0)
return ret;
*finished = ((t & 0x3) == 0x1) ? 1 : 0;
return 0;
}
static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
{
int err;
u8 ad_fini = 0;
if (gi == GI_945)
dprintk("try GI 945\n");
else if (gi == GI_595)
dprintk("try GI 595\n");
else if (gi == GI_420)
dprintk("try GI 420\n");
lgs8gxx_write_reg(priv, 0x04, gi);
lgs8gxx_soft_reset(priv);
msleep(50);
err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
if (err != 0)
return err;
if (ad_fini) {
err = lgs8gxx_is_locked(priv, locked);
if (err != 0)
return err;
}
return 0;
}
static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
u8 *detected_param, u8 *gi)
{
int i, j;
int err = 0;
u8 locked = 0, tmp_gi;
dprintk("%s\n", __func__);
lgs8gxx_set_mode_auto(priv);
/* Guard Interval */
lgs8gxx_write_reg(priv, 0x03, 00);
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
tmp_gi = GI_945;
err = lgs8gxx_autolock_gi(priv, GI_945, &locked);
if (err)
goto out;
if (locked)
goto locked;
}
for (j = 0; j < 2; j++) {
tmp_gi = GI_420;
err = lgs8gxx_autolock_gi(priv, GI_420, &locked);
if (err)
goto out;
if (locked)
goto locked;
}
tmp_gi = GI_595;
err = lgs8gxx_autolock_gi(priv, GI_595, &locked);
if (err)
goto out;
if (locked)
goto locked;
}
locked:
if ((err == 0) && (locked == 1)) {
u8 t;
lgs8gxx_read_reg(priv, 0xA2, &t);
*detected_param = t;
if (tmp_gi == GI_945)
dprintk("GI 945 locked\n");
else if (tmp_gi == GI_595)
dprintk("GI 595 locked\n");
else if (tmp_gi == GI_420)
dprintk("GI 420 locked\n");
*gi = tmp_gi;
}
if (!locked)
err = -1;
out:
return err;
}
static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
{
s8 err;
u8 gi = 0x2;
u8 detected_param = 0;
err = lgs8gxx_auto_detect(priv, &detected_param, &gi);
if (err != 0) {
dprintk("lgs8gxx_auto_detect failed\n");
}
/* Apply detected parameters */
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
u8 inter_leave_len = detected_param & TIM_MASK ;
inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40;
detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
detected_param |= inter_leave_len;
}
lgs8gxx_write_reg(priv, 0x7D, detected_param);
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
lgs8gxx_write_reg(priv, 0xC0, detected_param);
/* lgs8gxx_soft_reset(priv); */
/* Enter manual mode */
lgs8gxx_set_mode_manual(priv);
switch (gi) {
case GI_945:
priv->curr_gi = 945; break;
case GI_595:
priv->curr_gi = 595; break;
case GI_420:
priv->curr_gi = 420; break;
default:
priv->curr_gi = 945; break;
}
}
static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
u8 serial, u8 clk_pol, u8 clk_gated)
{
int ret = 0;
u8 t;
ret = lgs8gxx_read_reg(priv, 0xC2, &t);
if (ret != 0)
return ret;
t &= 0xF8;
t |= serial ? TS_SERIAL : TS_PARALLEL;
t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
ret = lgs8gxx_write_reg(priv, 0xC2, t);
if (ret != 0)
return ret;
return 0;
}
/* LGS8913 demod frontend functions */
static int lgs8913_init(struct lgs8gxx_state *priv)
{
u8 t;
/* LGS8913 specific */
lgs8gxx_write_reg(priv, 0xc1, 0x3);
lgs8gxx_read_reg(priv, 0x7c, &t);
lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);
/* LGS8913 specific */
lgs8gxx_read_reg(priv, 0xc3, &t);
lgs8gxx_write_reg(priv, 0xc3, t&0x10);
return 0;
}
static int lgs8gxx_init(struct dvb_frontend *fe)
{
struct lgs8gxx_state *priv =
(struct lgs8gxx_state *)fe->demodulator_priv;
const struct lgs8gxx_config *config = priv->config;
u8 data = 0;
s8 err;
dprintk("%s\n", __func__);
lgs8gxx_read_reg(priv, 0, &data);
dprintk("reg 0 = 0x%02X\n", data);
/* Setup MPEG output format */
err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
config->ts_clk_pol,
config->ts_clk_gated);
if (err != 0)
return -EIO;
if (config->prod == LGS8GXX_PROD_LGS8913)
lgs8913_init(priv);
lgs8gxx_set_if_freq(priv, priv->config->if_freq);
if (config->prod != LGS8GXX_PROD_LGS8913)
lgs8gxx_set_ad_mode(priv);
return 0;
}
static void lgs8gxx_release(struct dvb_frontend *fe)
{
struct lgs8gxx_state *state = fe->demodulator_priv;
dprintk("%s\n", __func__);
kfree(state);
}
static int lgs8gxx_write(struct dvb_frontend *fe, u8 *buf, int len)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
if (len != 2)
return -EINVAL;
return lgs8gxx_write_reg(priv, buf[0], buf[1]);
}
static int lgs8gxx_set_fe(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fe_params)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
dprintk("%s\n", __func__);
/* set frequency */
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, fe_params);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
/* start auto lock */
lgs8gxx_auto_lock(priv);
msleep(10);
return 0;
}
static int lgs8gxx_get_fe(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fe_params)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
u8 t;
dprintk("%s\n", __func__);
/* TODO: get real readings from device */
/* inversion status */
fe_params->inversion = INVERSION_OFF;
/* bandwidth */
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
lgs8gxx_read_reg(priv, 0x7D, &t);
fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
/* constellation */
switch (t & SC_MASK) {
case SC_QAM64:
fe_params->u.ofdm.constellation = QAM_64;
break;
case SC_QAM32:
fe_params->u.ofdm.constellation = QAM_32;
break;
case SC_QAM16:
fe_params->u.ofdm.constellation = QAM_16;
break;
case SC_QAM4:
case SC_QAM4NR:
fe_params->u.ofdm.constellation = QPSK;
break;
default:
fe_params->u.ofdm.constellation = QAM_64;
}
/* transmission mode */
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
/* guard interval */
fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
/* hierarchy */
fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
return 0;
}
static
int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *fesettings)
{
/* FIXME: copy from tda1004x.c */
fesettings->min_delay_ms = 800;
fesettings->step_size = 0;
fesettings->max_drift = 0;
return 0;
}
static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
s8 ret;
u8 t;
dprintk("%s\n", __func__);
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
if (ret != 0)
return -EIO;
dprintk("Reg 0x4B: 0x%02X\n", t);
*fe_status = 0;
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
if ((t & 0x40) == 0x40)
*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
if ((t & 0x80) == 0x80)
*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |
FE_HAS_LOCK;
} else {
if ((t & 0x80) == 0x80)
*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
}
/* success */
dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
return 0;
}
static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
{
u16 v;
u8 agc_lvl[2], cat;
dprintk("%s()\n", __func__);
lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);
lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);
v = agc_lvl[0];
v <<= 8;
v |= agc_lvl[1];
dprintk("agc_lvl: 0x%04X\n", v);
if (v < 0x100)
cat = 0;
else if (v < 0x190)
cat = 5;
else if (v < 0x2A8)
cat = 4;
else if (v < 0x381)
cat = 3;
else if (v < 0x400)
cat = 2;
else if (v == 0x400)
cat = 1;
else
cat = 0;
*signal = cat;
return 0;
}
static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
{
u8 t; s8 ret;
s16 max_strength = 0;
u8 str;
u16 i, gi = priv->curr_gi;
dprintk("%s\n", __func__);
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
if (ret != 0)
return -EIO;
if (fake_signal_str) {
if ((t & 0xC0) == 0xC0) {
dprintk("Fake signal strength as 50\n");
*signal = 0x32;
} else
*signal = 0;
return 0;
}
dprintk("gi = %d\n", gi);
for (i = 0; i < gi; i++) {
if ((i & 0xFF) == 0)
lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));
lgs8gxx_write_reg(priv, 0x83, i & 0xFF);
lgs8gxx_read_reg(priv, 0x94, &str);
if (max_strength < str)
max_strength = str;
}
*signal = max_strength;
dprintk("%s: signal=0x%02X\n", __func__, *signal);
lgs8gxx_read_reg(priv, 0x95, &t);
dprintk("%s: AVG Noise=0x%02X\n", __func__, t);
return 0;
}
static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
return lgs8913_read_signal_strength(priv, signal);
else
return lgs8gxx_read_signal_agc(priv, signal);
}
static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
u8 t;
*snr = 0;
lgs8gxx_read_reg(priv, 0x95, &t);
dprintk("AVG Noise=0x%02X\n", t);
*snr = 256 - t;
*snr <<= 8;
dprintk("snr=0x%x\n", *snr);
return 0;
}
static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
return 0;
}
static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
u8 r0, r1, r2, r3;
u32 total_cnt, err_cnt;
dprintk("%s\n", __func__);
lgs8gxx_write_reg(priv, 0xc6, 0x01);
lgs8gxx_write_reg(priv, 0xc6, 0x41);
lgs8gxx_write_reg(priv, 0xc6, 0x01);
msleep(200);
lgs8gxx_write_reg(priv, 0xc6, 0x81);
lgs8gxx_read_reg(priv, 0xd0, &r0);
lgs8gxx_read_reg(priv, 0xd1, &r1);
lgs8gxx_read_reg(priv, 0xd2, &r2);
lgs8gxx_read_reg(priv, 0xd3, &r3);
total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
lgs8gxx_read_reg(priv, 0xd4, &r0);
lgs8gxx_read_reg(priv, 0xd5, &r1);
lgs8gxx_read_reg(priv, 0xd6, &r2);
lgs8gxx_read_reg(priv, 0xd7, &r3);
err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
dprintk("error=%d total=%d\n", err_cnt, total_cnt);
if (total_cnt == 0)
*ber = 0;
else
*ber = err_cnt * 100 / total_cnt;
dprintk("%s: ber=0x%x\n", __func__, *ber);
return 0;
}
static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
if (priv->config->tuner_address == 0)
return 0;
if (enable) {
u8 v = 0x80 | priv->config->tuner_address;
return lgs8gxx_write_reg(priv, 0x01, v);
}
return lgs8gxx_write_reg(priv, 0x01, 0);
}
static struct dvb_frontend_ops lgs8gxx_ops = {
.info = {
.name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
.type = FE_OFDM,
.frequency_min = 474000000,
.frequency_max = 858000000,
.frequency_stepsize = 10000,
.caps =
FE_CAN_FEC_AUTO |
FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO
},
.release = lgs8gxx_release,
.init = lgs8gxx_init,
.write = lgs8gxx_write,
.i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
.set_frontend = lgs8gxx_set_fe,
.get_frontend = lgs8gxx_get_fe,
.get_tune_settings = lgs8gxx_get_tune_settings,
.read_status = lgs8gxx_read_status,
.read_ber = lgs8gxx_read_ber,
.read_signal_strength = lgs8gxx_read_signal_strength,
.read_snr = lgs8gxx_read_snr,
.read_ucblocks = lgs8gxx_read_ucblocks,
};
struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
struct i2c_adapter *i2c)
{
struct lgs8gxx_state *priv = NULL;
u8 data = 0;
dprintk("%s()\n", __func__);
if (config == NULL || i2c == NULL)
return NULL;
priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);
if (priv == NULL)
goto error_out;
priv->config = config;
priv->i2c = i2c;
/* check if the demod is there */
if (lgs8gxx_read_reg(priv, 0, &data) != 0) {
dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",
__func__, priv->config->demod_address);
goto error_out;
}
lgs8gxx_read_reg(priv, 1, &data);
memcpy(&priv->frontend.ops, &lgs8gxx_ops,
sizeof(struct dvb_frontend_ops));
priv->frontend.demodulator_priv = priv;
return &priv->frontend;
error_out:
dprintk("%s() error_out\n", __func__);
kfree(priv);
return NULL;
}
EXPORT_SYMBOL(lgs8gxx_attach);
MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
MODULE_LICENSE("GPL");
/*
* Support for Legend Silicon DMB-TH demodulator
* LGS8913, LGS8GL5
* experimental support LGS8G42, LGS8G52
*
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __LGS8GXX_H__
#define __LGS8GXX_H__
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
#define LGS8GXX_PROD_LGS8913 0
#define LGS8GXX_PROD_LGS8GL5 1
#define LGS8GXX_PROD_LGS8G42 3
#define LGS8GXX_PROD_LGS8G52 4
#define LGS8GXX_PROD_LGS8G54 5
struct lgs8gxx_config {
/* product type */
u8 prod;
/* the demodulator's i2c address */
u8 demod_address;
/* parallel or serial transport stream */
u8 serial_ts;
/* transport stream polarity*/
u8 ts_clk_pol;
/* transport stream clock gated by ts_valid */
u8 ts_clk_gated;
/* A/D Clock frequency */
u32 if_clk_freq; /* in kHz */
/* IF frequency */
u32 if_freq; /* in kHz */
/*Use External ADC*/
u8 ext_adc;
/*External ADC output two's complement*/
u8 adc_signed;
/*Sample IF data at falling edge of IF_CLK*/
u8 if_neg_edge;
/*IF use Negative center frequency*/
u8 if_neg_center;
/* slave address and configuration of the tuner */
u8 tuner_address;
};
#if defined(CONFIG_DVB_LGS8GXX) || \
(defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE))
extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
struct i2c_adapter *i2c);
#else
static inline
struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
struct i2c_adapter *i2c) {
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_LGS8GXX */
#endif /* __LGS8GXX_H__ */
/*
* Support for Legend Silicon DMB-TH demodulator
* LGS8913, LGS8GL5
* experimental support LGS8G42, LGS8G52
*
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef LGS8913_PRIV_H
#define LGS8913_PRIV_H
struct lgs8gxx_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct lgs8gxx_config *config;
struct dvb_frontend frontend;
u16 curr_gi; /* current guard interval */
};
#define SC_MASK 0x1C /* Sub-Carrier Modulation Mask */
#define SC_QAM64 0x10 /* 64QAM modulation */
#define SC_QAM32 0x0C /* 32QAM modulation */
#define SC_QAM16 0x08 /* 16QAM modulation */
#define SC_QAM4NR 0x04 /* 4QAM modulation */
#define SC_QAM4 0x00 /* 4QAM modulation */
#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */
#define LGS_FEC_0_4 0x00 /* FEC Rate 0.4 */
#define LGS_FEC_0_6 0x01 /* FEC Rate 0.6 */
#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */
#define TIM_MASK 0x20 /* Time Interleave Length Mask */
#define TIM_LONG 0x00 /* Time Interleave Length = 720 */
#define TIM_MIDDLE 0x20 /* Time Interleave Length = 240 */
#define CF_MASK 0x80 /* Control Frame Mask */
#define CF_EN 0x80 /* Control Frame On */
#define GI_MASK 0x03 /* Guard Interval Mask */
#define GI_420 0x00 /* 1/9 Guard Interval */
#define GI_595 0x01 /* */
#define GI_945 0x02 /* 1/4 Guard Interval */
#define TS_PARALLEL 0x00 /* Parallel TS Output a.k.a. SPI */
#define TS_SERIAL 0x01 /* Serial TS Output a.k.a. SSI */
#define TS_CLK_NORMAL 0x00 /* MPEG Clock Normal */
#define TS_CLK_INVERTED 0x02 /* MPEG Clock Inverted */
#define TS_CLK_GATED 0x00 /* MPEG clock gated */
#define TS_CLK_FREERUN 0x04 /* MPEG clock free running*/
#endif
......@@ -33,6 +33,9 @@
History:
Version 0.45:
Converted to v4l2_device.
Version 0.44:
Add suspend/resume functions, fix unplug of device,
a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
......@@ -88,7 +91,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <linux/usb.h>
......@@ -97,39 +100,8 @@
*/
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#define DRIVER_VERSION "v0.44"
#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
static struct v4l2_queryctrl radio_qctrl[] = {
{
.id = V4L2_CID_AUDIO_MUTE,
.name = "Mute",
.minimum = 0,
.maximum = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},
/* HINT: the disabled controls are only here to satify kradio and such apps */
{ .id = V4L2_CID_AUDIO_VOLUME,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BALANCE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BASS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_TREBLE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_LOUDNESS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
};
#define DRIVER_VERSION "v0.45"
#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
......@@ -167,6 +139,8 @@ module_param(radio_nr, int, 0);
struct dsbr100_device {
struct usb_device *usbdev;
struct video_device videodev;
struct v4l2_device v4l2_dev;
u8 *transfer_buffer;
struct mutex lock; /* buffer locking */
int curfreq;
......@@ -384,6 +358,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
mutex_unlock(&radio->lock);
video_unregister_device(&radio->videodev);
v4l2_device_disconnect(&radio->v4l2_dev);
}
......@@ -479,14 +454,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
int i;
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
if (qc->id && qc->id == radio_qctrl[i].id) {
memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
switch (qc->id) {
case V4L2_CID_AUDIO_MUTE:
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
}
return -EINVAL;
}
......@@ -656,6 +628,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
{
struct dsbr100_device *radio = videodev_to_radio(videodev);
v4l2_device_unregister(&radio->v4l2_dev);
kfree(radio->transfer_buffer);
kfree(radio);
}
......@@ -683,22 +656,15 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
};
/* V4L2 interface */
static struct video_device dsbr100_videodev_data = {
.name = "D-Link DSB-R 100",
.fops = &usb_dsbr100_fops,
.ioctl_ops = &usb_dsbr100_ioctl_ops,
.release = usb_dsbr100_video_device_release,
};
/* check if the device is present and register with v4l and usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct dsbr100_device *radio;
struct v4l2_device *v4l2_dev;
int retval;
radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
if (!radio)
return -ENOMEM;
......@@ -710,17 +676,35 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
return -ENOMEM;
}
v4l2_dev = &radio->v4l2_dev;
retval = v4l2_device_register(&intf->dev, v4l2_dev);
if (retval < 0) {
v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
kfree(radio->transfer_buffer);
kfree(radio);
return retval;
}
strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
radio->videodev.v4l2_dev = v4l2_dev;
radio->videodev.fops = &usb_dsbr100_fops;
radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
radio->videodev.release = usb_dsbr100_video_device_release;
mutex_init(&radio->lock);
radio->videodev = dsbr100_videodev_data;
radio->removed = 0;
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
video_set_drvdata(&radio->videodev, radio);
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (retval < 0) {
dev_err(&intf->dev, "couldn't register video device\n");
v4l2_err(v4l2_dev, "couldn't register video device\n");
v4l2_device_unregister(v4l2_dev);
kfree(radio->transfer_buffer);
kfree(radio);
return -EIO;
......
......@@ -355,20 +355,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int rtrack_open(struct file *file)
{
return 0;
}
static int rtrack_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
.open = rtrack_open,
.release = rtrack_release,
.ioctl = video_ioctl2,
};
......
......@@ -318,20 +318,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -EINVAL;
}
static int aztech_open(struct file *file)
{
return 0;
}
static int aztech_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
.open = aztech_open,
.release = aztech_release,
.ioctl = video_ioctl2,
};
......
......@@ -356,20 +356,8 @@ static struct pci_device_id gemtek_pci_id[] =
MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
static int gemtek_pci_open(struct file *file)
{
return 0;
}
static int gemtek_pci_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
.open = gemtek_pci_open,
.release = gemtek_pci_release,
.ioctl = video_ioctl2,
};
......
......@@ -375,20 +375,9 @@ static int gemtek_probe(struct gemtek *gt)
/*
* Video 4 Linux stuff.
*/
static int gemtek_open(struct file *file)
{
return 0;
}
static int gemtek_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
.open = gemtek_open,
.release = gemtek_release,
.ioctl = video_ioctl2,
};
......
......@@ -292,20 +292,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int maestro_open(struct file *file)
{
return 0;
}
static int maestro_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
.open = maestro_open,
.release = maestro_release,
.ioctl = video_ioctl2,
};
......
......@@ -339,20 +339,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -EINVAL;
}
static int maxiradio_open(struct file *file)
{
return 0;
}
static int maxiradio_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = maxiradio_open,
.release = maxiradio_release,
.ioctl = video_ioctl2,
};
......
......@@ -43,6 +43,7 @@
* Douglas Schilling Landgraf <dougsland@gmail.com> and
* David Ellingsworth <david@identd.dyndns.org>
* for discussion, help and support.
* Version 0.11: Converted to v4l2_device.
*
* Many things to do:
* - Correct power managment of device (suspend & resume)
......@@ -59,7 +60,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <linux/usb.h>
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
......@@ -67,8 +68,8 @@
/* driver and module definitions */
#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
#define DRIVER_VERSION "0.10"
#define RADIO_VERSION KERNEL_VERSION(0, 1, 0)
#define DRIVER_VERSION "0.11"
#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
......@@ -113,38 +114,6 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "Radio Nr");
static struct v4l2_queryctrl radio_qctrl[] = {
{
.id = V4L2_CID_AUDIO_MUTE,
.name = "Mute",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},
/* HINT: the disabled controls are only here to satify kradio and such apps */
{ .id = V4L2_CID_AUDIO_VOLUME,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BALANCE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BASS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_TREBLE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_LOUDNESS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
};
static int usb_amradio_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_amradio_disconnect(struct usb_interface *intf);
......@@ -159,6 +128,7 @@ struct amradio_device {
/* reference to USB and video device */
struct usb_device *usbdev;
struct video_device *videodev;
struct v4l2_device v4l2_dev;
unsigned char *buffer;
struct mutex lock; /* buffer locking */
......@@ -329,6 +299,7 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
video_unregister_device(radio->videodev);
v4l2_device_disconnect(&radio->v4l2_dev);
}
/* vidioc_querycap - query device capabilities */
......@@ -463,14 +434,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
int i;
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
if (qc->id && qc->id == radio_qctrl[i].id) {
memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
switch (qc->id) {
case V4L2_CID_AUDIO_MUTE:
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
}
return -EINVAL;
}
......@@ -671,34 +639,29 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
};
static void usb_amradio_device_release(struct video_device *videodev)
static void usb_amradio_video_device_release(struct video_device *videodev)
{
struct amradio_device *radio = video_get_drvdata(videodev);
/* we call v4l to free radio->videodev */
video_device_release(videodev);
v4l2_device_unregister(&radio->v4l2_dev);
/* free rest memory */
kfree(radio->buffer);
kfree(radio);
}
/* V4L2 interface */
static struct video_device amradio_videodev_template = {
.name = "AverMedia MR 800 USB FM Radio",
.fops = &usb_amradio_fops,
.ioctl_ops = &usb_amradio_ioctl_ops,
.release = usb_amradio_device_release,
};
/* check if the device is present and register with v4l and usb if it is */
static int usb_amradio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct amradio_device *radio;
struct v4l2_device *v4l2_dev;
int retval;
radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
if (!radio) {
dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
......@@ -713,6 +676,15 @@ static int usb_amradio_probe(struct usb_interface *intf,
return -ENOMEM;
}
v4l2_dev = &radio->v4l2_dev;
retval = v4l2_device_register(&intf->dev, v4l2_dev);
if (retval < 0) {
dev_err(&intf->dev, "couldn't register v4l2_device\n");
kfree(radio->buffer);
kfree(radio);
return retval;
}
radio->videodev = video_device_alloc();
if (!radio->videodev) {
......@@ -722,8 +694,11 @@ static int usb_amradio_probe(struct usb_interface *intf,
return -ENOMEM;
}
memcpy(radio->videodev, &amradio_videodev_template,
sizeof(amradio_videodev_template));
strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name));
radio->videodev->v4l2_dev = v4l2_dev;
radio->videodev->fops = &usb_amradio_fops;
radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops;
radio->videodev->release = usb_amradio_video_device_release;
radio->removed = 0;
radio->users = 0;
......@@ -734,10 +709,12 @@ static int usb_amradio_probe(struct usb_interface *intf,
mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (retval < 0) {
dev_err(&intf->dev, "could not register video device\n");
video_device_release(radio->videodev);
v4l2_device_unregister(v4l2_dev);
kfree(radio->buffer);
kfree(radio);
return -EIO;
......
......@@ -260,20 +260,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int rtrack2_open(struct file *file)
{
return 0;
}
static int rtrack2_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
.open = rtrack2_open,
.release = rtrack2_release,
.ioctl = video_ioctl2,
};
......
......@@ -260,20 +260,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int fmi_open(struct file *file)
{
return 0;
}
static int fmi_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
.open = fmi_open,
.release = fmi_release,
.ioctl = video_ioctl2,
};
......
......@@ -377,20 +377,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int fmr2_open(struct file *file)
{
return 0;
}
static int fmr2_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
.open = fmr2_open,
.release = fmr2_release,
.ioctl = video_ioctl2,
};
......
......@@ -1686,7 +1686,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* show some infos about the specific si470x device */
if (si470x_get_all_registers(radio) < 0) {
retval = -EIO;
goto err_all;
goto err_video;
}
printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[CHIPID]);
......@@ -1694,7 +1694,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* get software and hardware versions */
if (si470x_get_scratch_page_versions(radio) < 0) {
retval = -EIO;
goto err_all;
goto err_video;
}
printk(KERN_INFO DRIVER_NAME
": software version %d, hardware version %d\n",
......@@ -1727,7 +1727,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
if (!radio->buffer) {
retval = -EIO;
goto err_all;
goto err_video;
}
/* rds buffer configuration */
......@@ -1749,8 +1749,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
return 0;
err_all:
video_device_release(radio->videodev);
kfree(radio->buffer);
err_video:
video_device_release(radio->videodev);
err_radio:
kfree(radio);
err_initial:
......
......@@ -332,20 +332,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int terratec_open(struct file *file)
{
return 0;
}
static int terratec_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
.open = terratec_open,
.release = terratec_release,
.ioctl = video_ioctl2,
};
......
......@@ -338,20 +338,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int trust_open(struct file *file)
{
return 0;
}
static int trust_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
.open = trust_open,
.release = trust_release,
.ioctl = video_ioctl2,
};
......
......@@ -314,20 +314,8 @@ static int vidioc_log_status(struct file *file, void *priv)
return 0;
}
static int typhoon_open(struct file *file)
{
return 0;
}
static int typhoon_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
.open = typhoon_open,
.release = typhoon_release,
.ioctl = video_ioctl2,
};
......
......@@ -370,21 +370,9 @@ static int vidioc_s_audio(struct file *file, void *priv,
return a->index ? -EINVAL : 0;
}
static int zoltrix_open(struct file *file)
{
return 0;
}
static int zoltrix_release(struct file *file)
{
return 0;
}
static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
.open = zoltrix_open,
.release = zoltrix_release,
.ioctl = video_ioctl2,
};
......
......@@ -746,6 +746,18 @@ config SOC_CAMERA_OV772X
help
This is a ov772x camera driver
config MX1_VIDEO
bool
config VIDEO_MX1
tristate "i.MX1/i.MXL CMOS Sensor Interface driver"
depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA
select FIQ
select VIDEOBUF_DMA_CONTIG
select MX1_VIDEO
---help---
This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
config VIDEO_MX3
tristate "i.MX3x Camera Sensor Interface driver"
depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
......@@ -795,6 +807,8 @@ source "drivers/media/video/hdpvr/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
source "drivers/media/video/cx231xx/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
source "drivers/media/video/usbvideo/Kconfig"
......@@ -904,5 +918,4 @@ config USB_S2255
This driver can be compiled as a module, called s2255drv.
endif # V4L_USB_DRIVERS
endif # VIDEO_CAPTURE_DRIVERS
......@@ -10,7 +10,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
ifeq ($(CONFIG_COMPAT),y)
......@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
......@@ -133,6 +134,7 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
......
......@@ -219,18 +219,19 @@ static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int adv7170_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct adv7170 *encoder = to_adv7170(sd);
/* RJ: route->input = 0: input is from decoder
route->input = 1: input is from ZR36060
route->input = 2: color bar */
/* RJ: input = 0: input is from decoder
input = 1: input is from ZR36060
input = 2: color bar */
v4l2_dbg(1, debug, sd, "set input from %s\n",
route->input == 0 ? "decoder" : "ZR36060");
input == 0 ? "decoder" : "ZR36060");
switch (route->input) {
switch (input) {
case 0:
adv7170_write(sd, 0x01, 0x20);
adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */
......@@ -250,11 +251,11 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
break;
default:
v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
return -EINVAL;
}
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
encoder->input = route->input;
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
encoder->input = input;
return 0;
}
......
......@@ -237,15 +237,16 @@ static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int adv7175_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct adv7175 *encoder = to_adv7175(sd);
/* RJ: route->input = 0: input is from decoder
route->input = 1: input is from ZR36060
route->input = 2: color bar */
/* RJ: input = 0: input is from decoder
input = 1: input is from ZR36060
input = 2: color bar */
switch (route->input) {
switch (input) {
case 0:
adv7175_write(sd, 0x01, 0x00);
......@@ -288,11 +289,11 @@ static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
break;
default:
v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
return -EINVAL;
}
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
encoder->input = route->input;
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
encoder->input = input;
return 0;
}
......
......@@ -4,6 +4,7 @@ config VIDEO_AU0828
depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select VIDEOBUF_VMALLOC
select DVB_AU8522 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
......
......@@ -46,6 +46,7 @@ struct au0828_board au0828_boards[] = {
.name = "Hauppauge HVR850",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
.i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
.input = {
{
.type = AU0828_VMUX_TELEVISION,
......@@ -70,6 +71,13 @@ struct au0828_board au0828_boards[] = {
.name = "Hauppauge HVR950Q",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
/* The au0828 hardware i2c implementation does not properly
support the xc5000's i2c clock stretching. So we need to
lower the clock frequency enough where the 15us clock
stretch fits inside of a normal clock cycle, or else the
au0828 fails to set the STOP bit. A 30 KHz clock puts the
clock pulse width at 18us */
.i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
.input = {
{
.type = AU0828_VMUX_TELEVISION,
......@@ -94,16 +102,19 @@ struct au0828_board au0828_boards[] = {
.name = "Hauppauge HVR950Q rev xxF8",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
},
[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
.name = "DViCO FusionHDTV USB",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
},
};
......@@ -200,8 +211,8 @@ void au0828_card_setup(struct au0828_dev *dev)
/* Load the analog demodulator driver (note this would need to
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "au8522", "au8522",
0x8e >> 1);
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"au8522", "au8522", 0x8e >> 1);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
......@@ -209,8 +220,8 @@ void au0828_card_setup(struct au0828_dev *dev)
/* Setup tuners */
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "tuner", "tuner",
dev->board.tuner_addr);
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"tuner", "tuner", dev->board.tuner_addr);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
......
......@@ -36,8 +36,6 @@ int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
static atomic_t au0828_instance = ATOMIC_INIT(0);
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
......@@ -169,7 +167,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
int ifnum, retval, i;
int ifnum, retval;
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
......@@ -197,10 +195,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
usb_set_intfdata(interface, dev);
/* Create the v4l2_device */
i = atomic_inc_return(&au0828_instance) - 1;
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d",
"au0828", i);
retval = v4l2_device_register(&dev->usbdev->dev, &dev->v4l2_dev);
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
printk(KERN_ERR "%s() v4l2_device_register failed\n",
__func__);
......
......@@ -39,13 +39,15 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
{
struct au0828_dev *dev = i2c_adap->algo_data;
return au0828_read(dev, REG_201) & 0x08 ? 0 : 1;
return au0828_read(dev, AU0828_I2C_STATUS_201) &
AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1;
}
static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
{
struct au0828_dev *dev = i2c_adap->algo_data;
return au0828_read(dev, REG_201) & 0x02 ? 0 : 1;
return au0828_read(dev, AU0828_I2C_STATUS_201) &
AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1;
}
static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
......@@ -67,7 +69,8 @@ static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
{
struct au0828_dev *dev = i2c_adap->algo_data;
return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
return au0828_read(dev, AU0828_I2C_STATUS_201) &
AU0828_I2C_STATUS_READ_DONE ? 0 : 1;
}
static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
......@@ -89,7 +92,8 @@ static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
{
struct au0828_dev *dev = i2c_adap->algo_data;
return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
return au0828_read(dev, AU0828_I2C_STATUS_201) &
AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0;
}
static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
......@@ -111,7 +115,8 @@ static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
{
struct au0828_dev *dev = i2c_adap->algo_data;
return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
return au0828_read(dev, AU0828_I2C_STATUS_201) &
AU0828_I2C_STATUS_BUSY ? 1 : 0;
}
static int i2c_wait_done(struct i2c_adapter *i2c_adap)
......@@ -139,19 +144,14 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
dprintk(4, "%s()\n", __func__);
au0828_write(dev, REG_2FF, 0x01);
au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
/* FIXME: There is a problem with i2c communications with xc5000 that
requires us to slow down the i2c clock until we have a better
strategy (such as using the secondary i2c bus to do firmware
loading */
if ((msg->addr << 1) == 0xc2)
au0828_write(dev, REG_202, 0x40);
else
au0828_write(dev, REG_202, 0x07);
/* Set the I2C clock */
au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
dev->board.i2c_clk_divider);
/* Hardware needs 8 bit addresses */
au0828_write(dev, REG_203, msg->addr << 1);
au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
dprintk(4, "SEND: %02x\n", msg->addr);
......@@ -163,7 +163,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
actual bytes to the bus, just do a read check. This is
consistent with how I saw i2c device checking done in the
USB trace of the Windows driver */
au0828_write(dev, REG_200, 0x20);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_READ);
if (!i2c_wait_done(i2c_adap))
return -EIO;
......@@ -177,7 +179,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
dprintk(4, " %02x\n", msg->buf[i]);
au0828_write(dev, REG_205, msg->buf[i]);
au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
strobe++;
i++;
......@@ -186,9 +188,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
/* Strobe the byte into the bus */
if (i < msg->len)
au0828_write(dev, REG_200, 0x41);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_WRITE |
AU0828_I2C_TRIGGER_HOLD);
else
au0828_write(dev, REG_200, 0x01);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_WRITE);
/* Reset strobe trigger */
strobe = 0;
......@@ -216,25 +221,22 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
dprintk(4, "%s()\n", __func__);
au0828_write(dev, REG_2FF, 0x01);
au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
/* FIXME: There is a problem with i2c communications with xc5000 that
requires us to slow down the i2c clock until we have a better
strategy (such as using the secondary i2c bus to do firmware
loading */
if ((msg->addr << 1) == 0xc2)
au0828_write(dev, REG_202, 0x40);
else
au0828_write(dev, REG_202, 0x07);
/* Set the I2C clock */
au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
dev->board.i2c_clk_divider);
/* Hardware needs 8 bit addresses */
au0828_write(dev, REG_203, msg->addr << 1);
au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
dprintk(4, " RECV:\n");
/* Deal with i2c_scan */
if (msg->len == 0) {
au0828_write(dev, REG_200, 0x20);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_READ);
if (i2c_wait_read_ack(i2c_adap))
return -EIO;
return 0;
......@@ -245,14 +247,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
i++;
if (i < msg->len)
au0828_write(dev, REG_200, 0x60);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_READ |
AU0828_I2C_TRIGGER_HOLD);
else
au0828_write(dev, REG_200, 0x20);
au0828_write(dev, AU0828_I2C_TRIGGER_200,
AU0828_I2C_TRIGGER_READ);
if (!i2c_wait_read_done(i2c_adap))
return -EIO;
msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff;
msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
0xff;
dprintk(4, " %02x\n", msg->buf[i-1]);
}
......
......@@ -30,15 +30,36 @@
#define AU0828_SENSORCTRL_100 0x100
#define AU0828_SENSORCTRL_VBI_103 0x103
#define REG_200 0x200
#define REG_201 0x201
#define REG_202 0x202
#define REG_203 0x203
#define REG_205 0x205
#define REG_209 0x209
#define REG_2FF 0x2ff
/* I2C registers */
#define AU0828_I2C_TRIGGER_200 0x200
#define AU0828_I2C_STATUS_201 0x201
#define AU0828_I2C_CLK_DIVIDER_202 0x202
#define AU0828_I2C_DEST_ADDR_203 0x203
#define AU0828_I2C_WRITE_FIFO_205 0x205
#define AU0828_I2C_READ_FIFO_209 0x209
#define AU0828_I2C_MULTIBYTE_MODE_2FF 0x2ff
/* Audio registers */
#define AU0828_AUDIOCTRL_50C 0x50C
#define REG_600 0x600
/*********************************************************************/
/* Here are constants for values associated with the above registers */
/* I2C Trigger (Reg 0x200) */
#define AU0828_I2C_TRIGGER_WRITE 0x01
#define AU0828_I2C_TRIGGER_READ 0x20
#define AU0828_I2C_TRIGGER_HOLD 0x40
/* I2C Status (Reg 0x201) */
#define AU0828_I2C_STATUS_READ_DONE 0x01
#define AU0828_I2C_STATUS_NO_READ_ACK 0x02
#define AU0828_I2C_STATUS_WRITE_DONE 0x04
#define AU0828_I2C_STATUS_NO_WRITE_ACK 0x08
#define AU0828_I2C_STATUS_BUSY 0x10
/* I2C Clock Divider (Reg 0x202) */
#define AU0828_I2C_CLK_250KHZ 0x07
#define AU0828_I2C_CLK_100KHZ 0x14
#define AU0828_I2C_CLK_30KHZ 0x40
......@@ -1100,7 +1100,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_std, *norm);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
return 0;
}
......@@ -1154,7 +1154,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
int i;
struct v4l2_routing route;
dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
index);
......@@ -1180,9 +1179,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
break;
}
route.input = AUVI_INPUT(index).vmux;
route.output = 0;
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, &route);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
AUVI_INPUT(index).vmux, 0, 0);
for (i = 0; i < AU0828_MAX_INPUT; i++) {
int enable = 0;
......@@ -1205,8 +1203,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
}
}
route.input = AUVI_INPUT(index).amux;
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, &route);
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
AUVI_INPUT(index).amux, 0, 0);
return 0;
}
......
......@@ -81,6 +81,7 @@ struct au0828_board {
char *name;
unsigned int tuner_type;
unsigned char tuner_addr;
unsigned char i2c_clk_divider;
struct au0828_input input[AU0828_MAX_INPUT];
};
......
......@@ -292,21 +292,22 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int bt819_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct bt819 *decoder = to_bt819(sd);
v4l2_dbg(1, debug, sd, "set input %x\n", route->input);
v4l2_dbg(1, debug, sd, "set input %x\n", input);
if (route->input < 0 || route->input > 7)
if (input < 0 || input > 7)
return -EINVAL;
if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
v4l2_err(sd, "no notify found!\n");
if (decoder->input != route->input) {
if (decoder->input != input) {
v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
decoder->input = route->input;
decoder->input = input;
/* select mode */
if (decoder->input == 0) {
bt819_setbit(decoder, 0x0b, 6, 0);
......@@ -444,9 +445,6 @@ static const struct v4l2_subdev_core_ops bt819_core_ops = {
.g_ctrl = bt819_g_ctrl,
.s_ctrl = bt819_s_ctrl,
.queryctrl = bt819_queryctrl,
};
static const struct v4l2_subdev_tuner_ops bt819_tuner_ops = {
.s_std = bt819_s_std,
};
......@@ -459,7 +457,6 @@ static const struct v4l2_subdev_video_ops bt819_video_ops = {
static const struct v4l2_subdev_ops bt819_ops = {
.core = &bt819_core_ops,
.tuner = &bt819_tuner_ops,
.video = &bt819_video_ops,
};
......
......@@ -142,16 +142,17 @@ static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
static int bt856_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int bt856_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct bt856 *encoder = to_bt856(sd);
v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
v4l2_dbg(1, debug, sd, "set input %d\n", input);
/* We only have video bus.
* route->input= 0: input is from bt819
* route->input= 1: input is from ZR36060 */
switch (route->input) {
* input= 0: input is from bt819
* input= 1: input is from ZR36060 */
switch (input) {
case 0:
bt856_setbit(encoder, 0xde, 4, 0);
bt856_setbit(encoder, 0xde, 3, 1);
......
......@@ -99,7 +99,8 @@ static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int bt866_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
static const __u8 init[] = {
0xc8, 0xcc, /* CRSCALE */
......@@ -137,7 +138,7 @@ static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
val = encoder->reg[0xdc];
if (route->input == 0)
if (input == 0)
val |= 0x40; /* CBSWAP */
else
val &= ~0x40; /* !CBSWAP */
......@@ -145,15 +146,15 @@ static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
bt866_write(encoder, 0xdc, val);
val = encoder->reg[0xcc];
if (route->input == 2)
if (input == 2)
val |= 0x01; /* OSDBAR */
else
val &= ~0x01; /* !OSDBAR */
bt866_write(encoder, 0xcc, val);
v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
v4l2_dbg(1, debug, sd, "set input %d\n", input);
switch (route->input) {
switch (input) {
case 0:
case 1:
case 2:
......
......@@ -3324,17 +3324,6 @@ void __devinit bttv_init_card1(struct bttv *btv)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
static const unsigned short tvaudio_addrs[] = {
I2C_ADDR_TDA8425 >> 1,
I2C_ADDR_TEA6300 >> 1,
I2C_ADDR_TEA6420 >> 1,
I2C_ADDR_TDA9840 >> 1,
I2C_ADDR_TDA985x_L >> 1,
I2C_ADDR_TDA985x_H >> 1,
I2C_ADDR_TDA9874 >> 1,
I2C_ADDR_PIC16C54 >> 1,
I2C_CLIENT_END
};
int addr=ADDR_UNSET;
btv->tuner_type = UNSET;
......@@ -3512,12 +3501,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
"tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
"tuner", v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
tun_setup.type = btv->tuner_type;
......@@ -3570,8 +3562,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"saa6588", "saa6588", addrs);
sd = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "saa6588", "saa6588", addrs);
btv->has_saa6588 = (sd != NULL);
}
......@@ -3595,8 +3587,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"msp3400", "msp3400", addrs);
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "msp3400", "msp3400", addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
......@@ -3609,16 +3601,16 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"tda7432", "tda7432", addrs))
if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tda7432", "tda7432", addrs))
return;
goto no_audio;
}
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"tvaudio", "tvaudio", tvaudio_addrs);
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
......@@ -3637,21 +3629,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
it really is a msp3400, so it will return NULL when the device
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
static const unsigned short addrs[] = {
I2C_ADDR_MSP3400 >> 1,
I2C_CLIENT_END
};
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"msp3400", "msp3400", addrs);
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "msp3400", "msp3400",
I2C_ADDR_MSP3400 >> 1);
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
static const unsigned short addrs[] = {
I2C_ADDR_MSP3400_ALT >> 1,
I2C_CLIENT_END
};
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"msp3400", "msp3400", addrs);
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "msp3400", "msp3400",
I2C_ADDR_MSP3400_ALT >> 1);
}
/* If we found a msp34xx, then we're done. */
......@@ -3665,14 +3649,14 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"tda7432", "tda7432", addrs))
if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tda7432", "tda7432", addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
"tvaudio", "tvaudio", tvaudio_addrs);
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
if (btv->sd_tvaudio)
return;
......
......@@ -1198,7 +1198,7 @@ audio_mux(struct bttv *btv, int input, int mute)
ctrl.value = btv->mute;
bttv_call_all(btv, core, s_ctrl, &ctrl);
if (btv->sd_msp34xx) {
struct v4l2_routing route;
u32 in;
/* Note: the inputs tuner/radio/extern/intern are translated
to msp routings. This assumes common behavior for all msp3400
......@@ -1207,11 +1207,11 @@ audio_mux(struct bttv *btv, int input, int mute)
For now this is sufficient. */
switch (input) {
case TVAUDIO_INPUT_RADIO:
route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
break;
case TVAUDIO_INPUT_EXTERN:
route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
break;
case TVAUDIO_INPUT_INTERN:
......@@ -1220,7 +1220,7 @@ audio_mux(struct bttv *btv, int input, int mute)
input is the BTTV_BOARD_AVERMEDIA98. I wonder how
that was tested. My guess is that the whole INTERN
input does not work. */
route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
break;
case TVAUDIO_INPUT_TUNER:
......@@ -1229,21 +1229,18 @@ audio_mux(struct bttv *btv, int input, int mute)
is the only difference between the VOODOOTV_FM
and VOODOOTV_200 */
if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
else
route.input = MSP_INPUT_DEFAULT;
in = MSP_INPUT_DEFAULT;
break;
}
route.output = MSP_OUTPUT_DEFAULT;
v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, &route);
v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
in, MSP_OUTPUT_DEFAULT, 0);
}
if (btv->sd_tvaudio) {
struct v4l2_routing route;
route.input = input;
route.output = 0;
v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, &route);
v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
input, 0, 0);
}
return 0;
}
......@@ -1329,7 +1326,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
break;
}
id = tvnorm->v4l2_id;
bttv_call_all(btv, tuner, s_std, id);
bttv_call_all(btv, core, s_std, id);
return 0;
}
......
......@@ -26,7 +26,7 @@
#define _BTTVP_H_
#include <linux/version.h>
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18)
#include <linux/types.h>
#include <linux/wait.h>
......
......@@ -1954,7 +1954,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
goto out_freeirq;
cam->sensor_addr = 0x42;
cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter,
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
"ov7670", "ov7670", cam->sensor_addr);
if (cam->sensor == NULL) {
ret = -ENODEV;
......
......@@ -53,14 +53,15 @@ static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
return i2c_smbus_read_byte_data(client, reg);
}
static int cs5345_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int cs5345_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
if ((route->input & 0xf) > 6) {
v4l2_err(sd, "Invalid input %d.\n", route->input);
if ((input & 0xf) > 6) {
v4l2_err(sd, "Invalid input %d.\n", input);
return -EINVAL;
}
cs5345_write(sd, 0x09, route->input & 0xf);
cs5345_write(sd, 0x05, route->input & 0xf0);
cs5345_write(sd, 0x09, input & 0xf);
cs5345_write(sd, 0x05, input & 0xf0);
return 0;
}
......
......@@ -58,17 +58,18 @@ static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
return i2c_smbus_read_byte_data(client, reg);
}
static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
static int cs53l32a_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
/* There are 2 physical inputs, but the second input can be
placed in two modes, the first mode bypasses the PGA (gain),
the second goes through the PGA. Hence there are three
possible inputs to choose from. */
if (route->input > 2) {
v4l2_err(sd, "Invalid input %d.\n", route->input);
if (input > 2) {
v4l2_err(sd, "Invalid input %d.\n", input);
return -EINVAL;
}
cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
cs53l32a_write(sd, 0x01, 0x01 + (input << 4));
return 0;
}
......
......@@ -33,7 +33,6 @@
int cx18_audio_set_io(struct cx18 *cx)
{
const struct cx18_card_audio_input *in;
struct v4l2_routing route;
u32 val;
int err;
......@@ -44,13 +43,11 @@ int cx18_audio_set_io(struct cx18 *cx)
in = &cx->card->audio_inputs[cx->audio_input];
/* handle muxer chips */
route.input = in->muxer_input;
route.output = 0;
v4l2_subdev_call(cx->sd_extmux, audio, s_routing, &route);
v4l2_subdev_call(cx->sd_extmux, audio, s_routing,
in->audio_input, 0, 0);
route.input = in->audio_input;
err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl,
audio, s_routing, &route);
audio, s_routing, in->audio_input, 0, 0);
if (err)
return err;
......
......@@ -203,43 +203,42 @@ static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
switch (val) {
case CX18_AV_INIT_PLLS:
/*
* The crystal freq used in calculations in this driver will be
* 28.636360 MHz.
* Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
*/
/*
* The crystal freq used in calculations in this driver will be
* 28.636360 MHz.
* Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
*/
/*
* VDCLK Integer = 0x0f, Post Divider = 0x04
* AIMCLK Integer = 0x0e, Post Divider = 0x16
*/
cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
/*
* VDCLK Integer = 0x0f, Post Divider = 0x04
* AIMCLK Integer = 0x0e, Post Divider = 0x16
*/
cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
/* VDCLK Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
/* VDCLK Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
/* AIMCLK Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
/* AIMCLK Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
break;
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
return 0;
}
case CX18_AV_INIT_NORMAL:
default:
if (!state->is_initialized) {
/* initialize on first use */
state->is_initialized = 1;
cx18_av_initialize(cx);
}
break;
static int cx18_av_load_fw(struct v4l2_subdev *sd)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
if (!state->is_initialized) {
/* initialize on first use */
state->is_initialized = 1;
cx18_av_initialize(cx);
}
return 0;
}
......@@ -548,19 +547,19 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
}
static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
const struct v4l2_routing *route)
u32 input, u32 output, u32 config)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
return set_input(cx, route->input, state->aud_input);
return set_input(cx, input, state->aud_input);
}
static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
const struct v4l2_routing *route)
u32 input, u32 output, u32 config)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
return set_input(cx, state->vid_input, route->input);
return set_input(cx, state->vid_input, input);
}
static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
......@@ -1185,10 +1184,12 @@ static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
.g_chip_ident = cx18_av_g_chip_ident,
.log_status = cx18_av_log_status,
.init = cx18_av_init,
.load_fw = cx18_av_load_fw,
.reset = cx18_av_reset,
.queryctrl = cx18_av_queryctrl,
.g_ctrl = cx18_av_g_ctrl,
.s_ctrl = cx18_av_s_ctrl,
.s_std = cx18_av_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx18_av_g_register,
.s_register = cx18_av_s_register,
......@@ -1200,7 +1201,6 @@ static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
.s_frequency = cx18_av_s_frequency,
.g_tuner = cx18_av_g_tuner,
.s_tuner = cx18_av_s_tuner,
.s_std = cx18_av_s_std,
};
static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
......
......@@ -328,11 +328,6 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
return container_of(sd, struct cx18_av_state, sd);
}
enum cx18_av_subdev_init_arg {
CX18_AV_INIT_NORMAL = 0,
CX18_AV_INIT_PLLS = 1,
};
/* ----------------------------------------------------------------------- */
/* cx18_av-core.c */
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
......
......@@ -810,7 +810,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
CX18_ERR("Could not register A/V decoder subdevice\n");
goto free_map;
}
cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0);
/* Initialize GPIO Reset Controller to do chip resets during i2c init */
if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
......@@ -1028,7 +1028,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
/* Init the A/V decoder, if it hasn't been already */
v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_NORMAL);
v4l2_subdev_call(cx->sd_av, core, load_fw);
vf.tuner = 0;
vf.type = V4L2_TUNER_ANALOG_TV;
......
......@@ -608,7 +608,7 @@ int cx18_v4l2_close(struct file *filp)
/* Mark that the radio is no longer in use */
clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
/* Switch tuner to TV */
cx18_call_all(cx, tuner, s_std, cx->std);
cx18_call_all(cx, core, s_std, cx->std);
/* Select correct audio input (i.e. TV tuner or Line in) */
cx18_audio_set_io(cx);
if (atomic_read(&cx->ana_capturing) > 0) {
......
......@@ -156,12 +156,12 @@ static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
}
static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
const struct v4l2_routing *route)
u32 input, u32 output, u32 config)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
u32 data;
switch (route->input) {
switch (input) {
case 0:
data = cx->card->gpio_audio_input.tuner;
break;
......@@ -180,10 +180,10 @@ static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
.log_status = gpiomux_log_status,
.s_std = gpiomux_s_std,
};
static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
.s_std = gpiomux_s_std,
.s_radio = gpiomux_s_radio,
};
......
......@@ -100,16 +100,16 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
cx->card_i2c->radio);
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
adap, mod, type, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
cx->card_i2c->demod);
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
adap, mod, type, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
cx->card_i2c->tv);
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
adap, mod, type, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
......@@ -120,7 +120,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;
/* It's an I2C device other than an analog tuner */
sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
......
......@@ -705,7 +705,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
(unsigned long long) cx->std);
/* Tuner */
cx18_call_all(cx, tuner, s_std, cx->std);
cx18_call_all(cx, core, s_std, cx->std);
return 0;
}
......@@ -926,16 +926,6 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
switch (cmd) {
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
route->input, route->output);
cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing,
route);
break;
}
case VIDIOC_INT_RESET: {
u32 val = *(u32 *)arg;
......
......@@ -25,20 +25,8 @@
void cx18_video_set_io(struct cx18 *cx)
{
struct v4l2_routing route;
int inp = cx->active_input;
u32 type;
route.input = cx->card->video_inputs[inp].video_input;
route.output = 0;
v4l2_subdev_call(cx->sd_av, video, s_routing, &route);
type = cx->card->video_inputs[inp].video_type;
if (type == CX18_CARD_INPUT_VID_TUNER)
route.input = 0; /* Tuner */
else if (type < CX18_CARD_INPUT_COMPOSITE1)
route.input = 2; /* S-Video */
else
route.input = 1; /* Composite */
v4l2_subdev_call(cx->sd_av, video, s_routing,
cx->card->video_inputs[inp].video_input, 0, 0);
}
config VIDEO_CX231XX
tristate "Conexant cx231xx USB video capture support"
depends on VIDEO_DEV && I2C && INPUT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEOBUF_VMALLOC
select VIDEO_CX25840
select VIDEO_CX231XX_ALSA
---help---
This is a video4linux driver for Conexant 231xx USB based TV cards.
To compile this driver as a module, choose M here: the
module will be called cx231xx
config VIDEO_CX231XX_ALSA
tristate "Conexant Cx231xx ALSA audio module"
depends on VIDEO_CX231XX && SND
select SND_PCM
---help---
This is an ALSA driver for Cx231xx USB based TV cards.
To compile this driver as a module, choose M here: the
module will be called cx231xx-alsa
config VIDEO_CX231XX_DVB
tristate "DVB/ATSC Support for Cx231xx based TV cards"
depends on VIDEO_CX231XX && DVB_CORE
select VIDEOBUF_DVB
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Conexant cx231xx chips.
cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o
cx231xx-alsa-objs := cx231xx-audio.o
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
/*
* Conexant Cx231xx audio extension
*
* Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
* Based on em28xx driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/init.h>
#include <linux/sound.h>
#include <linux/spinlock.h>
#include <linux/soundcard.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/initval.h>
#include <sound/control.h>
#include <media/v4l2-common.h>
#include "cx231xx.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "cx231xx-audio %s: " fmt, \
__func__, ##arg); \
} while (0)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
{
int i;
dprintk("Stopping isoc\n");
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
if (dev->adev.urb[i]) {
if (!irqs_disabled())
usb_kill_urb(dev->adev.urb[i]);
else
usb_unlink_urb(dev->adev.urb[i]);
usb_free_urb(dev->adev.urb[i]);
dev->adev.urb[i] = NULL;
kfree(dev->adev.transfer_buffer[i]);
dev->adev.transfer_buffer[i] = NULL;
}
}
return 0;
}
static void cx231xx_audio_isocirq(struct urb *urb)
{
struct cx231xx *dev = urb->context;
int i;
unsigned int oldptr;
int period_elapsed = 0;
int status;
unsigned char *cp;
unsigned int stride;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:
case -ESHUTDOWN:
return;
default: /* error */
dprintk("urb completition error %d.\n", urb->status);
break;
}
if (dev->adev.capture_pcm_substream) {
substream = dev->adev.capture_pcm_substream;
runtime = substream->runtime;
stride = runtime->frame_bits >> 3;
for (i = 0; i < urb->number_of_packets; i++) {
int length = urb->iso_frame_desc[i].actual_length /
stride;
cp = (unsigned char *)urb->transfer_buffer +
urb->iso_frame_desc[i].offset;
if (!length)
continue;
oldptr = dev->adev.hwptr_done_capture;
if (oldptr + length >= runtime->buffer_size) {
unsigned int cnt;
cnt = runtime->buffer_size - oldptr;
memcpy(runtime->dma_area + oldptr * stride, cp,
cnt * stride);
memcpy(runtime->dma_area, cp + cnt * stride,
length * stride - cnt * stride);
} else {
memcpy(runtime->dma_area + oldptr * stride, cp,
length * stride);
}
snd_pcm_stream_lock(substream);
dev->adev.hwptr_done_capture += length;
if (dev->adev.hwptr_done_capture >=
runtime->buffer_size)
dev->adev.hwptr_done_capture -=
runtime->buffer_size;
dev->adev.capture_transfer_done += length;
if (dev->adev.capture_transfer_done >=
runtime->period_size) {
dev->adev.capture_transfer_done -=
runtime->period_size;
period_elapsed = 1;
}
snd_pcm_stream_unlock(substream);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
}
urb->status = 0;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
status);
}
return;
}
static int cx231xx_init_audio_isoc(struct cx231xx *dev)
{
int i, errCode;
int sb_size;
cx231xx_info("%s: Starting AUDIO transfers\n", __func__);
sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
struct urb *urb;
int j, k;
dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
if (!dev->adev.transfer_buffer[i])
return -ENOMEM;
memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
cx231xx_errdev("usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
usb_free_urb(dev->adev.urb[j]);
kfree(dev->adev.transfer_buffer[j]);
}
return -ENOMEM;
}
urb->dev = dev->udev;
urb->context = dev;
urb->pipe = usb_rcvisocpipe(dev->udev,
dev->adev.end_point_addr);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
urb->complete = cx231xx_audio_isocirq;
urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS;
urb->transfer_buffer_length = sb_size;
for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS;
j++, k += dev->adev.max_pkt_size) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
}
dev->adev.urb[i] = urb;
}
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
if (errCode < 0) {
cx231xx_isoc_audio_deinit(dev);
return errCode;
}
}
return errCode;
}
static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
{
dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
"stop" : "start");
switch (cmd) {
case CX231XX_CAPTURE_STREAM_EN:
if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
dev->adev.capture_stream = STREAM_ON;
cx231xx_init_audio_isoc(dev);
} else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
dev->adev.capture_stream = STREAM_OFF;
cx231xx_isoc_audio_deinit(dev);
} else {
cx231xx_errdev("An underrun very likely occurred. "
"Ignoring it.\n");
}
return 0;
default:
return -EINVAL;
}
}
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
size_t size)
{
struct snd_pcm_runtime *runtime = subs->runtime;
dprintk("Allocating vbuffer\n");
if (runtime->dma_area) {
if (runtime->dma_bytes > size)
return 0;
vfree(runtime->dma_area);
}
runtime->dma_area = vmalloc(size);
if (!runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 0;
}
static struct snd_pcm_hardware snd_cx231xx_hw_capture = {
.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
.period_bytes_min = 64, /* 12544/2, */
.period_bytes_max = 12544,
.periods_min = 2,
.periods_max = 98, /* 12544, */
};
static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
dprintk("opening device and trying to acquire exclusive lock\n");
if (!dev) {
cx231xx_errdev("BUG: cx231xx can't find device struct."
" Can't proceed with open\n");
return -ENODEV;
}
/* Sets volume, mute, etc */
dev->mute = 0;
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
if (ret < 0) {
cx231xx_errdev("failed to set alternate setting !\n");
return ret;
}
/* inform hardware to start streaming */
ret = cx231xx_capture_start(dev, 1, Audio);
runtime->hw = snd_cx231xx_hw_capture;
mutex_lock(&dev->lock);
dev->adev.users++;
mutex_unlock(&dev->lock);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
dev->adev.capture_pcm_substream = substream;
runtime->private_data = dev;
return 0;
}
static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
{
int ret;
struct cx231xx *dev = snd_pcm_substream_chip(substream);
dprintk("closing device\n");
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
if (ret < 0) {
cx231xx_errdev("failed to set alternate setting !\n");
return ret;
}
/* inform hardware to start streaming */
ret = cx231xx_capture_start(dev, 0, Audio);
dev->mute = 1;
mutex_lock(&dev->lock);
dev->adev.users--;
mutex_unlock(&dev->lock);
if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
dprintk("audio users: %d\n", dev->adev.users);
dprintk("disabling audio stream!\n");
dev->adev.shutdown = 0;
dprintk("released lock\n");
cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0);
}
return 0;
}
static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
unsigned int channels, rate, format;
int ret;
dprintk("Setting capture parameters\n");
ret = snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
format = params_format(hw_params);
rate = params_rate(hw_params);
channels = params_channels(hw_params);
/* TODO: set up cx231xx audio chip to deliver the correct audio format,
current default is 48000hz multiplexed => 96000hz mono
which shouldn't matter since analogue TV only supports mono */
return 0;
}
static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
dprintk("Stop capture, if needed\n");
if (dev->adev.capture_stream == STREAM_ON)
cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
return 0;
}
static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
{
return 0;
}
static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
int retval;
dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
"start" : "stop");
spin_lock(&dev->adev.slock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN,
CX231XX_START_AUDIO);
retval = 0;
break;
case SNDRV_PCM_TRIGGER_STOP:
cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
retval = 0;
break;
default:
retval = -EINVAL;
}
spin_unlock(&dev->adev.slock);
return retval;
}
static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
*substream)
{
struct cx231xx *dev;
unsigned long flags;
snd_pcm_uframes_t hwptr_done;
dev = snd_pcm_substream_chip(substream);
spin_lock_irqsave(&dev->adev.slock, flags);
hwptr_done = dev->adev.hwptr_done_capture;
spin_unlock_irqrestore(&dev->adev.slock, flags);
return hwptr_done;
}
static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
unsigned long offset)
{
void *pageptr = subs->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
static struct snd_pcm_ops snd_cx231xx_pcm_capture = {
.open = snd_cx231xx_capture_open,
.close = snd_cx231xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_cx231xx_hw_capture_params,
.hw_free = snd_cx231xx_hw_capture_free,
.prepare = snd_cx231xx_prepare,
.trigger = snd_cx231xx_capture_trigger,
.pointer = snd_cx231xx_capture_pointer,
.page = snd_pcm_get_vmalloc_page,
};
static int cx231xx_audio_init(struct cx231xx *dev)
{
struct cx231xx_audio *adev = &dev->adev;
struct snd_pcm *pcm;
struct snd_card *card;
static int devnr;
int err;
struct usb_interface *uif;
int i, isoc_pipe = 0;
if (dev->has_alsa_audio != 1) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
return 0;
}
cx231xx_info("cx231xx-audio.c: probing for cx231xx "
"non standard usbaudio\n");
err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
0, &card);
if (err < 0)
return err;
spin_lock_init(&adev->slock);
err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
if (err < 0) {
snd_card_free(card);
return err;
}
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_cx231xx_pcm_capture);
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture");
strcpy(card->driver, "Conexant cx231xx Audio");
strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio");
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
adev->sndcard = card;
adev->udev = dev->udev;
/* compute alternate max packet sizes for Audio */
uif =
dev->udev->actconfig->interface[dev->current_pcb_config.
hs_config_info[0].interface_info.
audio_index + 1];
adev->end_point_addr =
le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
bEndpointAddress);
adev->num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
adev->end_point_addr, adev->num_alt);
adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL);
if (adev->alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
return -ENOMEM;
}
for (i = 0; i < adev->num_alt; i++) {
u16 tmp =
le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
wMaxPacketSize);
adev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
cx231xx_info("Alternate setting %i, max size= %i\n", i,
adev->alt_max_pkt_size[i]);
}
return 0;
}
static int cx231xx_audio_fini(struct cx231xx *dev)
{
if (dev == NULL)
return 0;
if (dev->has_alsa_audio != 1) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
return 0;
}
if (dev->adev.sndcard) {
snd_card_free(dev->adev.sndcard);
kfree(dev->adev.alt_max_pkt_size);
dev->adev.sndcard = NULL;
}
return 0;
}
static struct cx231xx_ops audio_ops = {
.id = CX231XX_AUDIO,
.name = "Cx231xx Audio Extension",
.init = cx231xx_audio_init,
.fini = cx231xx_audio_fini,
};
static int __init cx231xx_alsa_register(void)
{
return cx231xx_register_extension(&audio_ops);
}
static void __exit cx231xx_alsa_unregister(void)
{
cx231xx_unregister_extension(&audio_ops);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
MODULE_DESCRIPTION("Cx231xx Audio driver");
module_init(cx231xx_alsa_register);
module_exit(cx231xx_alsa_unregister);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
cx231xx_vbi.h - driver for Conexant Cx23100/101/102 USB video capture devices
Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
Based on cx88 driver
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _CX231XX_VBI_H
#define _CX231XX_VBI_H
extern struct videobuf_queue_ops cx231xx_vbi_qops;
#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */
#define NTSC_VBI_END_LINE 21
#define NTSC_VBI_LINES (NTSC_VBI_END_LINE-NTSC_VBI_START_LINE+1)
#define PAL_VBI_START_LINE 6
#define PAL_VBI_END_LINE 23
#define PAL_VBI_LINES (PAL_VBI_END_LINE-PAL_VBI_START_LINE+1)
#define VBI_STRIDE 1440
#define VBI_SAMPLES_PER_LINE 1440
#define CX231XX_NUM_VBI_PACKETS 4
#define CX231XX_NUM_VBI_BUFS 5
/* stream functions */
int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct cx231xx *dev,
struct urb *urb));
void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
/* vbi data copy functions */
u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
u8 sav_eav, u8 *p_buffer, u32 buffer_size);
u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
u8 *p_line, u32 length, int field_number);
void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
struct cx231xx_dmaqueue *dma_q);
int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
u8 *p_buffer, u32 bytes_to_copy);
u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
struct cx231xx_dmaqueue *dma_q);
#endif
此差异已折叠。
此差异已折叠。
......@@ -739,9 +739,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", "cx25840", 0x88 >> 1);
v4l2_subdev_call(dev->sd_cx25840, core, init, 0);
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
break;
}
......
......@@ -875,7 +875,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
cx23885_card_setup(dev);
call_all(dev, core, s_standby, 0);
call_all(dev, tuner, s_standby);
cx23885_ir_init(dev);
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
......
......@@ -673,7 +673,7 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->callback = cx23885_tuner_callback;
/* Put the analog decoder in standby to keep it quiet */
call_all(dev, core, s_standby, 0);
call_all(dev, tuner, s_standby);
if (fe0->dvb.frontend->ops.analog_ops.standby)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
......
......@@ -299,7 +299,7 @@ static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
dev->tvnorm = norm;
call_all(dev, tuner, s_std, norm);
call_all(dev, core, s_std, norm);
return 0;
}
......@@ -393,9 +393,6 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
{
struct v4l2_routing route;
memset(&route, 0, sizeof(route));
dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
__func__,
input, INPUT(input)->vmux,
......@@ -403,10 +400,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
INPUT(input)->gpio2, INPUT(input)->gpio3);
dev->input = input;
route.input = INPUT(input)->vmux;
/* Tell the internal A/V decoder */
v4l2_subdev_call(dev->sd_cx25840, video, s_routing, &route);
v4l2_subdev_call(dev->sd_cx25840, video, s_routing,
INPUT(input)->vmux, 0, 0);
return 0;
}
......@@ -1523,10 +1519,12 @@ int cx23885_video_register(struct cx23885_dev *dev)
struct v4l2_subdev *sd = NULL;
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->i2c_bus[1].i2c_adap,
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
"tuner", "tuner", dev->tuner_addr);
else
sd = v4l2_i2c_new_probed_subdev(&dev->i2c_bus[1].i2c_adap,
sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
"tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;
......
......@@ -37,7 +37,7 @@
#include <linux/version.h>
#include <linux/mutex.h>
#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 1)
#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2)
#define UNSET (-1U)
......
......@@ -50,6 +50,7 @@ struct cx25840_state {
u32 rev;
int is_cx25836;
int is_cx23885;
int is_cx231xx;
int is_initialized;
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
struct work_struct fw_work; /* work entry for fw load */
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册