diff options
Diffstat (limited to 'drivers/media/common')
27 files changed, 6707 insertions, 1847 deletions
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 121b0110af3..b85f88c8ddb 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -1,3 +1,25 @@ +# Used by common drivers, when they need to ask questions +config MEDIA_COMMON_OPTIONS + bool + +comment "common driver options" + depends on MEDIA_COMMON_OPTIONS + +config VIDEO_CX2341X + tristate + +config VIDEO_BTCX + depends on PCI + tristate + +config VIDEO_TVEEPROM + tristate + depends on I2C + +config CYPRESS_FIRMWARE + tristate "Cypress firmware helper routines" + depends on USB + source "drivers/media/common/b2c2/Kconfig" source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index b8e2e3a33a3..d208de3b7cc 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1 +1,5 @@ obj-y += b2c2/ saa7146/ siano/ +obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o +obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o +obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o +obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig index 1df9e578daa..a8c6cdfaa2f 100644 --- a/drivers/media/common/b2c2/Kconfig +++ b/drivers/media/common/b2c2/Kconfig @@ -17,11 +17,6 @@ config DVB_B2C2_FLEXCOP select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the digital TV receiver chip made by B2C2 Inc. included in - Technisats PCI cards and USB boxes. - - Say Y if you own such a device and want to use it. # Selected via the PCI or USB flexcop drivers config DVB_B2C2_FLEXCOP_DEBUG diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 850a6c60675..7e14e90d292 100644 --- a/drivers/media/common/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c @@ -325,7 +325,7 @@ static int skystar2_rev27_attach(struct flexcop_device *fc, /* enable no_base_addr - no repeated start when reading */ fc->fc_i2c_adap[2].no_base_addr = 1; if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 1, 1)) { + 0x08, 1, 1, false)) { err("ISL6421 could NOT be attached"); goto fail_isl; } @@ -391,7 +391,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc, fc->fc_i2c_adap[2].no_base_addr = 1; if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 0, 0)) { + 0x08, 0, 0, false)) { err("ISL6421 could NOT be attached"); fc->fc_i2c_adap[2].no_base_addr = 0; return 0; diff --git a/drivers/media/common/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c index f2199e43e80..185c285f70f 100644 --- a/drivers/media/common/b2c2/flexcop-sram.c +++ b/drivers/media/common/b2c2/flexcop-sram.c @@ -85,7 +85,7 @@ static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 * while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; - }; + } if (retries == 0) printk("%s: SRAM timeout\n", __func__); @@ -110,7 +110,7 @@ static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; - }; + } if (retries == 0) printk("%s: SRAM timeout\n", __func__); @@ -122,7 +122,7 @@ static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; - }; + } if (retries == 0) printk("%s: SRAM timeout\n", __func__); diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/common/btcx-risc.c new file mode 100644 index 00000000000..ac1b2687a20 --- /dev/null +++ b/drivers/media/common/btcx-risc.c @@ -0,0 +1,260 @@ +/* + + btcx-risc.c + + bt848/bt878/cx2388x risc code generator. + + (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] + + 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/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/videodev2.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#include "btcx-risc.h" + +MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); + +/* ---------------------------------------------------------- */ +/* allocate/free risc memory */ + +static int memcnt; + +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc) +{ + if (NULL == risc->cpu) + return; + if (debug) { + memcnt--; + printk("btcx: riscmem free [%d] dma=%lx\n", + memcnt, (unsigned long)risc->dma); + } + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + memset(risc,0,sizeof(*risc)); +} + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size) +{ + __le32 *cpu; + dma_addr_t dma = 0; + + if (NULL != risc->cpu && risc->size < size) + btcx_riscmem_free(pci,risc); + if (NULL == risc->cpu) { + cpu = pci_alloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + if (debug) { + memcnt++; + printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", + memcnt, (unsigned long)dma, cpu, size); + } + } + memset(risc->cpu,0,risc->size); + return 0; +} + +/* ---------------------------------------------------------- */ +/* screen overlay helpers */ + +int +btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n) +{ + if (win->left < 0) { + /* left */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = -win->left; + clips[n].c.height = win->height; + n++; + } + if (win->left + win->width > swidth) { + /* right */ + clips[n].c.left = swidth - win->left; + clips[n].c.top = 0; + clips[n].c.width = win->width - clips[n].c.left; + clips[n].c.height = win->height; + n++; + } + if (win->top < 0) { + /* top */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = win->width; + clips[n].c.height = -win->top; + n++; + } + if (win->top + win->height > sheight) { + /* bottom */ + clips[n].c.left = 0; + clips[n].c.top = sheight - win->top; + clips[n].c.width = win->width; + clips[n].c.height = win->height - clips[n].c.top; + n++; + } + return n; +} + +int +btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) +{ + s32 nx,nw,dx; + unsigned int i; + + /* fixup window */ + nx = (win->left + mask) & ~mask; + nw = (win->width) & ~mask; + if (nx + nw > win->left + win->width) + nw -= mask+1; + dx = nx - win->left; + win->left = nx; + win->width = nw; + if (debug) + printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", + win->width, win->height, win->left, win->top, dx); + + /* fixup clips */ + for (i = 0; i < n; i++) { + nx = (clips[i].c.left-dx) & ~mask; + nw = (clips[i].c.width) & ~mask; + if (nx + nw < clips[i].c.left-dx + clips[i].c.width) + nw += mask+1; + clips[i].c.left = nx; + clips[i].c.width = nw; + if (debug) + printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", + clips[i].c.width, clips[i].c.height, + clips[i].c.left, clips[i].c.top); + } + return 0; +} + +void +btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) +{ + struct v4l2_clip swap; + int i,j,n; + + if (nclips < 2) + return; + for (i = nclips-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (clips[j].c.left > clips[j+1].c.left) { + swap = clips[j]; + clips[j] = clips[j+1]; + clips[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + +void +btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips) +{ + unsigned int clip,skip; + int end, maxline; + + skip=0; + maxline = 9999; + for (clip = 0; clip < nclips; clip++) { + + /* sanity checks */ + if (clips[clip].c.left + clips[clip].c.width <= 0) + continue; + if (clips[clip].c.left > (signed)width) + break; + + /* vertical range */ + if (line > clips[clip].c.top+clips[clip].c.height-1) + continue; + if (line < clips[clip].c.top) { + if (maxline > clips[clip].c.top-1) + maxline = clips[clip].c.top-1; + continue; + } + if (maxline > clips[clip].c.top+clips[clip].c.height-1) + maxline = clips[clip].c.top+clips[clip].c.height-1; + + /* horizontal range */ + if (0 == skip || clips[clip].c.left > skips[skip-1].end) { + /* new one */ + skips[skip].start = clips[clip].c.left; + if (skips[skip].start < 0) + skips[skip].start = 0; + skips[skip].end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip].end > width) + skips[skip].end = width; + skip++; + } else { + /* overlaps -- expand last one */ + end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip-1].end < end) + skips[skip-1].end = end; + if (skips[skip-1].end > width) + skips[skip-1].end = width; + } + } + *nskips = skip; + *maxy = maxline; + + if (debug) { + printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); + for (skip = 0; skip < *nskips; skip++) { + printk(" %d-%d",skips[skip].start,skips[skip].end); + } + printk("\n"); + } +} + +/* ---------------------------------------------------------- */ + +EXPORT_SYMBOL(btcx_riscmem_alloc); +EXPORT_SYMBOL(btcx_riscmem_free); + +EXPORT_SYMBOL(btcx_screen_clips); +EXPORT_SYMBOL(btcx_align); +EXPORT_SYMBOL(btcx_sort_clips); +EXPORT_SYMBOL(btcx_calc_skips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h new file mode 100644 index 00000000000..f8bc6e8e7b5 --- /dev/null +++ b/drivers/media/common/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c new file mode 100644 index 00000000000..103ef6bad2e --- /dev/null +++ b/drivers/media/common/cx2341x.c @@ -0,0 +1,1726 @@ +/* + * cx2341x - generic code for cx23415/6/8 based devices + * + * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <media/tuner.h> +#include <media/cx2341x.h> +#include <media/v4l2-common.h> + +MODULE_DESCRIPTION("cx23415/6/8 driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +/********************** COMMON CODE *********************/ + +/* definitions for audio properties bits 29-28 */ +#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 +#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 +#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 + +static const char *cx2341x_get_name(u32 id) +{ + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return "Spatial Filter Mode"; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + return "Spatial Filter"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + return "Spatial Luma Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + return "Spatial Chroma Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return "Temporal Filter Mode"; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + return "Temporal Filter"; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return "Median Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + return "Median Luma Filter Maximum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + return "Median Luma Filter Minimum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + return "Median Chroma Filter Maximum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + return "Median Chroma Filter Minimum"; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return "Insert Navigation Packets"; + } + return NULL; +} + +static const char **cx2341x_get_menu(u32 id) +{ + static const char *cx2341x_video_spatial_filter_mode_menu[] = { + "Manual", + "Auto", + NULL + }; + + static const char *cx2341x_video_luma_spatial_filter_type_menu[] = { + "Off", + "1D Horizontal", + "1D Vertical", + "2D H/V Separable", + "2D Symmetric non-separable", + NULL + }; + + static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = { + "Off", + "1D Horizontal", + NULL + }; + + static const char *cx2341x_video_temporal_filter_mode_menu[] = { + "Manual", + "Auto", + NULL + }; + + static const char *cx2341x_video_median_filter_type_menu[] = { + "Off", + "Horizontal", + "Vertical", + "Horizontal/Vertical", + "Diagonal", + NULL + }; + + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return cx2341x_video_spatial_filter_mode_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + return cx2341x_video_luma_spatial_filter_type_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + return cx2341x_video_chroma_spatial_filter_type_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return cx2341x_video_temporal_filter_mode_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_video_median_filter_type_menu; + } + return NULL; +} + +static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags) +{ + *name = cx2341x_get_name(id); + *flags = 0; + + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + *type = V4L2_CTRL_TYPE_MENU; + *min = 0; + *step = 0; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + *type = V4L2_CTRL_TYPE_BOOLEAN; + *min = 0; + *max = *step = 1; + break; + default: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + } + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + *flags |= V4L2_CTRL_FLAG_UPDATE; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + *flags |= V4L2_CTRL_FLAG_SLIDER; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + } +} + + +/********************** OLD CODE *********************/ + +/* Must be sorted from low to high control ID! */ +const u32 cx2341x_mpeg_ctrls[] = { + V4L2_CID_MPEG_CLASS, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_CID_MPEG_STREAM_VBI_FMT, + V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_CID_MPEG_AUDIO_MODE, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, + V4L2_CID_MPEG_AUDIO_EMPHASIS, + V4L2_CID_MPEG_AUDIO_CRC, + V4L2_CID_MPEG_AUDIO_MUTE, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_CID_MPEG_VIDEO_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, + V4L2_CID_MPEG_VIDEO_MUTE, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, + V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, + 0 +}; +EXPORT_SYMBOL(cx2341x_mpeg_ctrls); + +static const struct cx2341x_mpeg_params default_params = { + /* misc */ + .capabilities = 0, + .port = CX2341X_PORT_MEMORY, + .width = 720, + .height = 480, + .is_50hz = 0, + + /* stream */ + .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, + .stream_insert_nav_packets = 0, + + /* audio */ + .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, + .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, + .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, + .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, + .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, + .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, + .audio_mute = 0, + + /* video */ + .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, + .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, + .video_b_frames = 2, + .video_gop_size = 12, + .video_gop_closure = 1, + .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .video_bitrate = 6000000, + .video_bitrate_peak = 8000000, + .video_temporal_decimation = 0, + .video_mute = 0, + .video_mute_yuv = 0x008080, /* YCbCr value for black */ + + /* encoding filters */ + .video_spatial_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter = 0, + .video_luma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_temporal_filter = 8, + .video_median_filter_type = + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_luma_median_filter_top = 255, + .video_luma_median_filter_bottom = 0, + .video_chroma_median_filter_top = 255, + .video_chroma_median_filter_bottom = 0, +}; +/* Map the control ID to the correct field in the cx2341x_mpeg_params + struct. Return -EINVAL if the ID is unknown, else return 0. */ +static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + ctrl->value = params->audio_sampling_freq; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + ctrl->value = params->audio_encoding; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + ctrl->value = params->audio_l2_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + ctrl->value = params->audio_ac3_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_MODE: + ctrl->value = params->audio_mode; + break; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + ctrl->value = params->audio_mode_extension; + break; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + ctrl->value = params->audio_emphasis; + break; + case V4L2_CID_MPEG_AUDIO_CRC: + ctrl->value = params->audio_crc; + break; + case V4L2_CID_MPEG_AUDIO_MUTE: + ctrl->value = params->audio_mute; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + ctrl->value = params->video_encoding; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + ctrl->value = params->video_aspect; + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + ctrl->value = params->video_b_frames; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctrl->value = params->video_gop_size; + break; + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + ctrl->value = params->video_gop_closure; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + ctrl->value = params->video_bitrate_mode; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctrl->value = params->video_bitrate; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + ctrl->value = params->video_bitrate_peak; + break; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + ctrl->value = params->video_temporal_decimation; + break; + case V4L2_CID_MPEG_VIDEO_MUTE: + ctrl->value = params->video_mute; + break; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: + ctrl->value = params->video_mute_yuv; + break; + case V4L2_CID_MPEG_STREAM_TYPE: + ctrl->value = params->stream_type; + break; + case V4L2_CID_MPEG_STREAM_VBI_FMT: + ctrl->value = params->stream_vbi_fmt; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + ctrl->value = params->video_spatial_filter_mode; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + ctrl->value = params->video_spatial_filter; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + ctrl->value = params->video_luma_spatial_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + ctrl->value = params->video_chroma_spatial_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + ctrl->value = params->video_temporal_filter_mode; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + ctrl->value = params->video_temporal_filter; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + ctrl->value = params->video_median_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + ctrl->value = params->video_luma_median_filter_top; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + ctrl->value = params->video_luma_median_filter_bottom; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + ctrl->value = params->video_chroma_median_filter_top; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + ctrl->value = params->video_chroma_median_filter_bottom; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + ctrl->value = params->stream_insert_nav_packets; + break; + default: + return -EINVAL; + } + return 0; +} + +/* Map the control ID to the correct field in the cx2341x_mpeg_params + struct. Return -EINVAL if the ID is unknown, else return 0. */ +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; + params->audio_sampling_freq = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (busy) + return -EBUSY; + if (params->capabilities & CX2341X_CAP_HAS_AC3) + if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) + return -ERANGE; + params->audio_encoding = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; + params->audio_l2_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (busy) + return -EBUSY; + if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) + return -EINVAL; + params->audio_ac3_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MODE: + params->audio_mode = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + params->audio_mode_extension = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + params->audio_emphasis = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_CRC: + params->audio_crc = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MUTE: + params->audio_mute = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + params->video_aspect = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: { + int b = ctrl->value + 1; + int gop = params->video_gop_size; + params->video_b_frames = ctrl->value; + params->video_gop_size = b * ((gop + b - 1) / b); + /* Max GOP size = 34 */ + while (params->video_gop_size > 34) + params->video_gop_size -= b; + break; + } + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: { + int b = params->video_b_frames + 1; + int gop = ctrl->value; + params->video_gop_size = b * ((gop + b - 1) / b); + /* Max GOP size = 34 */ + while (params->video_gop_size > 34) + params->video_gop_size -= b; + ctrl->value = params->video_gop_size; + break; + } + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + params->video_gop_closure = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; + /* MPEG-1 only allows CBR */ + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && + ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + return -EINVAL; + params->video_bitrate_mode = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; + params->video_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; + params->video_bitrate_peak = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + params->video_temporal_decimation = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_MUTE: + params->video_mute = (ctrl->value != 0); + break; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: + params->video_mute_yuv = ctrl->value; + break; + case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; + params->stream_type = ctrl->value; + params->video_encoding = + (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + /* MPEG-1 implies CBR */ + params->video_bitrate_mode = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + break; + case V4L2_CID_MPEG_STREAM_VBI_FMT: + params->stream_vbi_fmt = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + params->video_spatial_filter_mode = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + params->video_spatial_filter = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + params->video_luma_spatial_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + params->video_chroma_spatial_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + params->video_temporal_filter_mode = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + params->video_temporal_filter = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + params->video_median_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + params->video_luma_median_filter_top = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + params->video_luma_median_filter_bottom = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + params->video_chroma_median_filter_top = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + params->video_chroma_median_filter_bottom = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + params->stream_insert_nav_packets = ctrl->value; + break; + default: + return -EINVAL; + } + return 0; +} + +static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, + s32 min, s32 max, s32 step, s32 def) +{ + const char *name; + + switch (qctrl->id) { + /* MPEG controls */ + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type, + &min, &max, &step, &def, &qctrl->flags); + qctrl->minimum = min; + qctrl->maximum = max; + qctrl->step = step; + qctrl->default_value = def; + qctrl->reserved[0] = qctrl->reserved[1] = 0; + strlcpy(qctrl->name, name, sizeof(qctrl->name)); + return 0; + + default: + return v4l2_ctrl_query_fill(qctrl, min, max, step, def); + } +} + +int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, + struct v4l2_queryctrl *qctrl) +{ + int err; + + switch (qctrl->id) { + case V4L2_CID_MPEG_CLASS: + return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); + case V4L2_CID_MPEG_STREAM_TYPE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS); + + case V4L2_CID_MPEG_STREAM_VBI_FMT: + if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, + V4L2_MPEG_STREAM_VBI_FMT_NONE); + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, + default_params.stream_vbi_fmt); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + /* + * The state of L2 & AC3 bitrate controls can change + * when this control changes, but v4l2_ctrl_query_fill() + * already sets V4L2_CTRL_FLAG_UPDATE for + * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. + */ + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_AC3, 1, + default_params.audio_encoding); + } + + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, + default_params.audio_encoding); + + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_L2_BITRATE_192K, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, + default_params.audio_l2_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3 && + params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_AUDIO_MODE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_STEREO, + V4L2_MPEG_AUDIO_MODE_MONO, 1, + V4L2_MPEG_AUDIO_MODE_STEREO); + + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); + if (err == 0 && + params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_EMPHASIS_NONE, + V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, + V4L2_MPEG_AUDIO_EMPHASIS_NONE); + + case V4L2_CID_MPEG_AUDIO_CRC: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_CRC_NONE, + V4L2_MPEG_AUDIO_CRC_CRC16, 1, + V4L2_MPEG_AUDIO_CRC_NONE); + + case V4L2_CID_MPEG_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); + + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_48K, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, + default_params.audio_ac3_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + if (params->audio_encoding != + V4L2_MPEG_AUDIO_ENCODING_AC3) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } else + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + case V4L2_CID_MPEG_VIDEO_ENCODING: + /* this setting is read-only for the cx2341x since the + V4L2_CID_MPEG_STREAM_TYPE really determines the + MPEG-1/2 setting */ + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ENCODING_MPEG_1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + if (err == 0) + qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return err; + + case V4L2_CID_MPEG_VIDEO_ASPECT: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ASPECT_1x1, + V4L2_MPEG_VIDEO_ASPECT_221x100, 1, + V4L2_MPEG_VIDEO_ASPECT_4x3); + + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); + + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, + params->is_50hz ? 12 : 15); + + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); + + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); + if (err == 0 && + params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); + + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); + if (err == 0 && + params->video_bitrate_mode == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); + + case V4L2_CID_MPEG_VIDEO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); + + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ + return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); + + /* CX23415/6 specific */ + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, + default_params.video_spatial_filter_mode); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, + default_params.video_spatial_filter); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 1, + default_params.video_luma_spatial_filter_type); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 1, + default_params.video_chroma_spatial_filter_type); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, + default_params.video_temporal_filter_mode); + + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, + default_params.video_temporal_filter); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_temporal_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, + default_params.video_median_filter_type); + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_top); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_bottom); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_top); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_bottom); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, + default_params.stream_insert_nav_packets); + + default: + return -EINVAL; + + } +} +EXPORT_SYMBOL(cx2341x_ctrl_query); + +const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) +{ + static const char * const mpeg_stream_type_without_ts[] = { + "MPEG-2 Program Stream", + "", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + + static const char *mpeg_stream_type_with_ts[] = { + "MPEG-2 Program Stream", + "MPEG-2 Transport Stream", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + + static const char *mpeg_audio_encoding_l2_ac3[] = { + "", + "MPEG-1/2 Layer II", + "", + "", + "AC-3", + NULL + }; + + switch (id) { + case V4L2_CID_MPEG_STREAM_TYPE: + return (p->capabilities & CX2341X_CAP_HAS_TS) ? + mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; + case V4L2_CID_MPEG_AUDIO_ENCODING: + return (p->capabilities & CX2341X_CAP_HAS_AC3) ? + mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: + return NULL; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_get_menu(id); + default: + return v4l2_ctrl_get_menu(id); + } +} +EXPORT_SYMBOL(cx2341x_ctrl_get_menu); + +static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) +{ + params->audio_properties = + (params->audio_sampling_freq << 0) | + (params->audio_mode << 8) | + (params->audio_mode_extension << 10) | + (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + ? 3 : params->audio_emphasis) << 12) | + (params->audio_crc << 14); + + if ((params->capabilities & CX2341X_CAP_HAS_AC3) && + params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { + params->audio_properties |= + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | + (params->audio_ac3_bitrate << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + params->audio_properties |= + ((3 - params->audio_encoding) << 2) | + ((1 + params->audio_l2_bitrate) << 4); + } +} + +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, + struct v4l2_ext_controls *ctrls, unsigned int cmd) +{ + int err = 0; + int i; + + if (cmd == VIDIOC_G_EXT_CTRLS) { + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + err = cx2341x_get_ctrl(params, ctrl); + if (err) { + ctrls->error_idx = i; + break; + } + } + return err; + } + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + struct v4l2_queryctrl qctrl; + const char * const *menu_items = NULL; + + qctrl.id = ctrl->id; + err = cx2341x_ctrl_query(params, &qctrl); + if (err) + break; + if (qctrl.type == V4L2_CTRL_TYPE_MENU) + menu_items = cx2341x_ctrl_get_menu(params, qctrl.id); + err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); + if (err) + break; + err = cx2341x_set_ctrl(params, busy, ctrl); + if (err) + break; + } + if (err == 0 && + params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + params->video_bitrate_peak < params->video_bitrate) { + err = -ERANGE; + ctrls->error_idx = ctrls->count; + } + if (err) + ctrls->error_idx = i; + else + cx2341x_calc_audio_properties(params); + return err; +} +EXPORT_SYMBOL(cx2341x_ext_ctrls); + +void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) +{ + *p = default_params; + cx2341x_calc_audio_properties(p); +} +EXPORT_SYMBOL(cx2341x_fill_defaults); + +static int cx2341x_api(void *priv, cx2341x_mbox_func func, + u32 cmd, int args, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i; + + va_start(vargs, args); + + for (i = 0; i < args; i++) + data[i] = va_arg(vargs, int); + va_end(vargs); + return func(priv, cmd, args, 0, data); +} + +#define NEQ(field) (old->field != new->field) + +int cx2341x_update(void *priv, cx2341x_mbox_func func, + const struct cx2341x_mpeg_params *old, + const struct cx2341x_mpeg_params *new) +{ + static int mpeg_stream_type[] = { + 0, /* MPEG-2 PS */ + 1, /* MPEG-2 TS */ + 2, /* MPEG-1 SS */ + 14, /* DVD */ + 11, /* VCD */ + 12, /* SVCD */ + }; + + int err = 0; + int force = (old == NULL); + u16 temporal = new->video_temporal_filter; + + cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); + + if (force || NEQ(is_50hz)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, + new->is_50hz); + if (err) return err; + } + + if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { + u16 w = new->width; + u16 h = new->height; + + if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + w /= 2; + h /= 2; + } + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, + h, w); + if (err) return err; + } + if (force || NEQ(stream_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, + mpeg_stream_type[new->stream_type]); + if (err) return err; + } + if (force || NEQ(video_aspect)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, + 1 + new->video_aspect); + if (err) return err; + } + if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, + new->video_gop_size, new->video_b_frames + 1); + if (err) return err; + } + if (force || NEQ(video_gop_closure)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, + new->video_gop_closure); + if (err) return err; + } + if (force || NEQ(audio_properties)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, + 1, new->audio_properties); + if (err) return err; + } + if (force || NEQ(audio_mute)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, + new->audio_mute); + if (err) return err; + } + if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || + NEQ(video_bitrate_peak)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, + new->video_bitrate_mode, new->video_bitrate, + new->video_bitrate_peak / 400, 0, 0); + if (err) return err; + } + if (force || NEQ(video_spatial_filter_mode) || + NEQ(video_temporal_filter_mode) || + NEQ(video_median_filter_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, + 2, new->video_spatial_filter_mode | + (new->video_temporal_filter_mode << 1), + new->video_median_filter_type); + if (err) return err; + } + if (force || NEQ(video_luma_median_filter_bottom) || + NEQ(video_luma_median_filter_top) || + NEQ(video_chroma_median_filter_bottom) || + NEQ(video_chroma_median_filter_top)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, + new->video_luma_median_filter_bottom, + new->video_luma_median_filter_top, + new->video_chroma_median_filter_bottom, + new->video_chroma_median_filter_top); + if (err) return err; + } + if (force || NEQ(video_luma_spatial_filter_type) || + NEQ(video_chroma_spatial_filter_type)) { + err = cx2341x_api(priv, func, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, + 2, new->video_luma_spatial_filter_type, + new->video_chroma_spatial_filter_type); + if (err) return err; + } + if (force || NEQ(video_spatial_filter) || + old->video_temporal_filter != temporal) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, + 2, new->video_spatial_filter, temporal); + if (err) return err; + } + if (force || NEQ(video_temporal_decimation)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, + 1, new->video_temporal_decimation); + if (err) return err; + } + if (force || NEQ(video_mute) || + (new->video_mute && NEQ(video_mute_yuv))) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, + new->video_mute | (new->video_mute_yuv << 8)); + if (err) return err; + } + if (force || NEQ(stream_insert_nav_packets)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, + 7, new->stream_insert_nav_packets); + if (err) return err; + } + return 0; +} +EXPORT_SYMBOL(cx2341x_update); + +static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id) +{ + const char * const *menu = cx2341x_ctrl_get_menu(p, id); + struct v4l2_ext_control ctrl; + + if (menu == NULL) + goto invalid; + ctrl.id = id; + if (cx2341x_get_ctrl(p, &ctrl)) + goto invalid; + while (ctrl.value-- && *menu) menu++; + if (*menu == NULL) + goto invalid; + return *menu; + +invalid: + return "<invalid>"; +} + +void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) +{ + int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + + /* Stream */ + printk(KERN_INFO "%s: Stream: %s", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); + if (p->stream_insert_nav_packets) + printk(" (with navigation packets)"); + printk("\n"); + printk(KERN_INFO "%s: VBI Format: %s\n", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); + + /* Video */ + printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", + prefix, + p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), + p->is_50hz ? 25 : 30, + (p->video_mute) ? " (muted)" : ""); + printk(KERN_INFO "%s: Video: %s, %s, %s, %d", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), + p->video_bitrate); + if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + printk(", Peak %d", p->video_bitrate_peak); + printk("\n"); + printk(KERN_INFO + "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", + prefix, + p->video_gop_size, p->video_b_frames, + p->video_gop_closure ? "" : "No "); + if (p->video_temporal_decimation) + printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", + prefix, p->video_temporal_decimation); + + /* Audio */ + printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), + cx2341x_menu_item(p, + p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 + ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE + : V4L2_CID_MPEG_AUDIO_L2_BITRATE), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), + p->audio_mute ? " (muted)" : ""); + if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + printk(", %s", cx2341x_menu_item(p, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); + printk(", %s, %s\n", + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); + + /* Encoding filters */ + printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), + p->video_spatial_filter); + + printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), + p->video_temporal_filter); + printk(KERN_INFO + "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), + p->video_luma_median_filter_bottom, + p->video_luma_median_filter_top, + p->video_chroma_median_filter_bottom, + p->video_chroma_median_filter_top); +} +EXPORT_SYMBOL(cx2341x_log_status); + + + +/********************** NEW CODE *********************/ + +static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct cx2341x_handler, hdl); +} + +static int cx2341x_hdl_api(struct cx2341x_handler *hdl, + u32 cmd, int args, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i; + + va_start(vargs, args); + + for (i = 0; i < args; i++) + data[i] = va_arg(vargs, int); + va_end(vargs); + return hdl->func(hdl->priv, cmd, args, 0, data); +} + +/* ctrl->handler->lock is held, so it is safe to access cur.val */ +static inline int cx2341x_neq(struct v4l2_ctrl *ctrl) +{ + return ctrl && ctrl->val != ctrl->cur.val; +} + +static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct cx2341x_handler *hdl = to_cxhdl(ctrl); + s32 val = ctrl->val; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_B_FRAMES: { + /* video gop cluster */ + int b = val + 1; + int gop = hdl->video_gop_size->val; + + gop = b * ((gop + b - 1) / b); + + /* Max GOP size = 34 */ + while (gop > 34) + gop -= b; + hdl->video_gop_size->val = gop; + break; + } + + case V4L2_CID_MPEG_STREAM_TYPE: + /* stream type cluster */ + hdl->video_encoding->val = + (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + /* MPEG-1 implies CBR */ + hdl->video_bitrate_mode->val = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + /* peak bitrate shall be >= normal bitrate */ + if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + hdl->video_bitrate_peak->val < hdl->video_bitrate->val) + hdl->video_bitrate_peak->val = hdl->video_bitrate->val; + break; + } + return 0; +} + +static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl) +{ + static const int mpeg_stream_type[] = { + 0, /* MPEG-2 PS */ + 1, /* MPEG-2 TS */ + 2, /* MPEG-1 SS */ + 14, /* DVD */ + 11, /* VCD */ + 12, /* SVCD */ + }; + struct cx2341x_handler *hdl = to_cxhdl(ctrl); + s32 val = ctrl->val; + u32 props; + int err; + + switch (ctrl->id) { + case V4L2_CID_MPEG_STREAM_VBI_FMT: + if (hdl->ops && hdl->ops->s_stream_vbi_fmt) + return hdl->ops->s_stream_vbi_fmt(hdl, val); + return 0; + + case V4L2_CID_MPEG_VIDEO_ASPECT: + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1); + + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val); + + case V4L2_CID_MPEG_AUDIO_MUTE: + return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val); + + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val); + + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + /* audio properties cluster */ + props = (hdl->audio_sampling_freq->val << 0) | + (hdl->audio_mode->val << 8) | + (hdl->audio_mode_extension->val << 10) | + (hdl->audio_crc->val << 14); + if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + props |= 3 << 12; + else + props |= hdl->audio_emphasis->val << 12; + + if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) { + props |= +#if 1 + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | +#endif + (hdl->audio_ac3_bitrate->val << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + props |= + ((3 - hdl->audio_encoding->val) << 2) | + ((1 + hdl->audio_l2_bitrate->val) << 4); + } + err = cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props); + if (err) + return err; + + hdl->audio_properties = props; + if (hdl->audio_ac3_bitrate) { + int is_ac3 = hdl->audio_encoding->val == + V4L2_MPEG_AUDIO_ENCODING_AC3; + + v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3); + v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3); + } + v4l2_ctrl_activate(hdl->audio_mode_extension, + hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO); + if (cx2341x_neq(hdl->audio_sampling_freq) && + hdl->ops && hdl->ops->s_audio_sampling_freq) + return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val); + if (cx2341x_neq(hdl->audio_mode) && + hdl->ops && hdl->ops->s_audio_mode) + return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val); + return 0; + + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + /* video gop cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2, + hdl->video_gop_size->val, + hdl->video_b_frames->val + 1); + + case V4L2_CID_MPEG_STREAM_TYPE: + /* stream type cluster */ + err = cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]); + if (err) + return err; + + err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5, + hdl->video_bitrate_mode->val, + hdl->video_bitrate->val, + hdl->video_bitrate_peak->val / 400, 0, 0); + if (err) + return err; + + v4l2_ctrl_activate(hdl->video_bitrate_mode, + hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1); + v4l2_ctrl_activate(hdl->video_bitrate_peak, + hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + if (cx2341x_neq(hdl->video_encoding) && + hdl->ops && hdl->ops->s_video_encoding) + return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val); + return 0; + + case V4L2_CID_MPEG_VIDEO_MUTE: + /* video mute cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1, + hdl->video_mute->val | + (hdl->video_mute_yuv->val << 8)); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: { + int active_filter; + + /* video filter mode */ + err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, + hdl->video_spatial_filter_mode->val | + (hdl->video_temporal_filter_mode->val << 1), + hdl->video_median_filter_type->val); + if (err) + return err; + + active_filter = hdl->video_spatial_filter_mode->val != + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO; + v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter); + v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter); + active_filter = hdl->video_temporal_filter_mode->val != + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO; + v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter); + active_filter = hdl->video_median_filter_type->val != + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF; + v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter); + v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter); + return 0; + } + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + /* video filter type cluster */ + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, + hdl->video_luma_spatial_filter_type->val, + hdl->video_chroma_spatial_filter_type->val); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + /* video filter cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, + hdl->video_spatial_filter->val, + hdl->video_temporal_filter->val); + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + /* video median cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4, + hdl->video_luma_median_filter_bottom->val, + hdl->video_luma_median_filter_top->val, + hdl->video_chroma_median_filter_bottom->val, + hdl->video_chroma_median_filter_top->val); + } + return -EINVAL; +} + +static const struct v4l2_ctrl_ops cx2341x_ops = { + .try_ctrl = cx2341x_try_ctrl, + .s_ctrl = cx2341x_s_ctrl, +}; + +static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, + u32 id, s32 min, s32 max, s32 step, s32 def) +{ + struct v4l2_ctrl_config cfg; + + cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags); + cfg.ops = &cx2341x_ops; + cfg.id = id; + cfg.min = min; + cfg.max = max; + cfg.def = def; + if (cfg.type == V4L2_CTRL_TYPE_MENU) { + cfg.step = 0; + cfg.menu_skip_mask = step; + cfg.qmenu = cx2341x_get_menu(id); + } else { + cfg.step = step; + cfg.menu_skip_mask = 0; + } + return v4l2_ctrl_new_custom(hdl, &cfg, NULL); +} + +static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl, + u32 id, s32 min, s32 max, s32 step, s32 def) +{ + return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def); +} + +static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl, + u32 id, s32 max, s32 mask, s32 def) +{ + return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def); +} + +int cx2341x_handler_init(struct cx2341x_handler *cxhdl, + unsigned nr_of_controls_hint) +{ + struct v4l2_ctrl_handler *hdl = &cxhdl->hdl; + u32 caps = cxhdl->capabilities; + int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI; + int has_ac3 = caps & CX2341X_CAP_HAS_AC3; + int has_ts = caps & CX2341X_CAP_HAS_TS; + + cxhdl->width = 720; + cxhdl->height = 480; + + v4l2_ctrl_handler_init(hdl, nr_of_controls_hint); + + /* Add controls in ascending control ID order for fastest + insertion time. */ + cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS); + cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_STREAM_VBI_FMT, + V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2, + V4L2_MPEG_STREAM_VBI_FMT_NONE); + cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2); + cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff, + V4L2_MPEG_AUDIO_L2_BITRATE_224K); + cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_MODE, + V4L2_MPEG_AUDIO_MODE_MONO, 0, + V4L2_MPEG_AUDIO_MODE_STEREO); + cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); + cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_EMPHASIS, + V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0, + V4L2_MPEG_AUDIO_EMPHASIS_NONE); + cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_CRC, + V4L2_MPEG_AUDIO_CRC_CRC16, 0, + V4L2_MPEG_AUDIO_CRC_NONE); + + cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0); + if (has_ac3) + cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03, + V4L2_MPEG_AUDIO_AC3_BITRATE_224K); + cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_MPEG_VIDEO_ASPECT_221x100, 0, + V4L2_MPEG_VIDEO_ASPECT_4x3); + cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2); + cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 1, 34, 1, cxhdl->is_50hz ? 12 : 15); + cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); + cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); + cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, 27000000, 1, 6000000); + cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + 0, 27000000, 1, 8000000); + cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0); + cxhdl->video_mute = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0); + cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080); + + /* CX23415/6 specific */ + cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, + 0, 15, 1, 0); + cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 0, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR); + cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 0, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR); + cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, + 0, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, + 0, 31, 1, 8); + cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, + 0, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, + 0, 255, 1, 0); + cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, + 0, 255, 1, 255); + cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, + 0, 255, 1, 0); + cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, + 0, 255, 1, 255); + cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, + 0, 1, 1, 0); + + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + return err; + } + + v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq); + v4l2_ctrl_cluster(2, &cxhdl->video_b_frames); + v4l2_ctrl_cluster(5, &cxhdl->stream_type); + v4l2_ctrl_cluster(2, &cxhdl->video_mute); + v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode); + v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type); + v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter); + v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top); + + return 0; +} +EXPORT_SYMBOL(cx2341x_handler_init); + +void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz) +{ + cxhdl->is_50hz = is_50hz; + cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15; +} +EXPORT_SYMBOL(cx2341x_handler_set_50hz); + +int cx2341x_handler_setup(struct cx2341x_handler *cxhdl) +{ + int h = cxhdl->height; + int w = cxhdl->width; + int err; + + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0); + if (err) + return err; + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz); + if (err) + return err; + + if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + w /= 2; + h /= 2; + } + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); + if (err) + return err; + return v4l2_ctrl_handler_setup(&cxhdl->hdl); +} +EXPORT_SYMBOL(cx2341x_handler_setup); + +void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy) +{ + v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy); + v4l2_ctrl_grab(cxhdl->audio_encoding, busy); + v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy); + v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy); + v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy); + v4l2_ctrl_grab(cxhdl->stream_type, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy); +} +EXPORT_SYMBOL(cx2341x_handler_set_busy); diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c new file mode 100644 index 00000000000..577e82058fd --- /dev/null +++ b/drivers/media/common/cypress_firmware.c @@ -0,0 +1,132 @@ +/* cypress_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/firmware.h> +#include "cypress_firmware.h" + +struct usb_cypress_controller { + u8 id; + const char *name; /* name of the usb controller */ + u16 cs_reg; /* needs to be restarted, + * when the firmware has been downloaded */ +}; + +static const struct usb_cypress_controller cypress[] = { + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +static int cypress_get_hexline(const struct firmware *fw, + struct hexline *hx, int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + + if (*pos >= fw->size) + return 0; + + memset(hx, 0, sizeof(struct hexline)); + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data + * field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); + } + + memcpy(hx->data, &b[data_offs], hx->len); + hx->chk = b[hx->len + data_offs]; + *pos += hx->len + 5; + + return *pos; +} + +int cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) +{ + struct hexline *hx; + int ret, pos = 0; + + hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); + if (!hx) { + dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME); + return -ENOMEM; + } + + /* stop the CPU */ + hx->data[0] = 1; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); + if (ret != 1) { + dev_err(&udev->dev, "%s: CPU stop failed=%d\n", + KBUILD_MODNAME, ret); + ret = -EIO; + goto err_kfree; + } + + /* write firmware to memory */ + for (;;) { + ret = cypress_get_hexline(fw, hx, &pos); + if (ret < 0) + goto err_kfree; + else if (ret == 0) + break; + + ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len); + if (ret < 0) { + goto err_kfree; + } else if (ret != hx->len) { + dev_err(&udev->dev, + "%s: error while transferring firmware (transferred size=%d, block size=%d)\n", + KBUILD_MODNAME, ret, hx->len); + ret = -EIO; + goto err_kfree; + } + } + + /* start the CPU */ + hx->data[0] = 0; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); + if (ret != 1) { + dev_err(&udev->dev, "%s: CPU start failed=%d\n", + KBUILD_MODNAME, ret); + ret = -EIO; + goto err_kfree; + } + + ret = 0; +err_kfree: + kfree(hx); + return ret; +} +EXPORT_SYMBOL(cypress_load_firmware); + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Cypress firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/cypress_firmware.h b/drivers/media/common/cypress_firmware.h new file mode 100644 index 00000000000..e493cbc7a52 --- /dev/null +++ b/drivers/media/common/cypress_firmware.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#ifndef CYPRESS_FIRMWARE_H +#define CYPRESS_FIRMWARE_H + +#define CYPRESS_AN2135 0 +#define CYPRESS_AN2235 1 +#define CYPRESS_FX2 2 + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; + +int cypress_load_firmware(struct usb_device *, const struct firmware *, int); + +#endif diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index bb6ee5191eb..34b0d0ddeef 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -411,7 +411,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent saa7146_write(dev, MC2, 0xf8000000); /* request an interrupt for the saa7146 */ - err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED, + err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED, dev->name, dev); if (err < 0) { ERR("request_irq() failed\n"); @@ -524,8 +524,6 @@ static void saa7146_remove_one(struct pci_dev *pdev) DEB_EE("dev:%p\n", dev); dev->ext->detach(dev); - /* Zero the PCI drvdata after use. */ - pci_set_drvdata(pdev, NULL); /* shut down all video dma transfers */ saa7146_write(dev, MC1, 0x00ff0000); diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index b3890bd49df..eda01bc68ab 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -105,7 +105,7 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, } q->curr->vb.state = state; - do_gettimeofday(&q->curr->vb.ts); + v4l2_get_timestamp(&q->curr->vb.ts); wake_up(&q->curr->vb.done); q->curr = NULL; @@ -265,8 +265,7 @@ static int fops_release(struct file *file) DEB_EE("file:%p\n", file); - if (mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; + mutex_lock(vdev->lock); if (vdev->vfl_type == VFL_TYPE_VBI) { if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4143d61f79b..30779498c17 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1,7 +1,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <media/saa7146_vv.h> -#include <media/v4l2-chip-ident.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> #include <linux/module.h> @@ -832,7 +831,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) } */ -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct saa7146_vv *vv = dev->vv_data; @@ -856,7 +855,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) } for (i = 0; i < dev->ext_vv_data->num_stds; i++) - if (*id & dev->ext_vv_data->stds[i].id) + if (id & dev->ext_vv_data->stds[i].id) break; if (i != dev->ext_vv_data->num_stds) { vv->standard = &dev->ext_vv_data->stds[i]; @@ -988,26 +987,6 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty return err; } -static int vidioc_g_chip_ident(struct file *file, void *__fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct saa7146_fh *fh = __fh; - struct saa7146_dev *dev = fh->dev; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(&chip->match)) - chip->ident = V4L2_IDENT_SAA7146; - return 0; - } - if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && - chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - return v4l2_device_call_until_err(&dev->v4l2_dev, 0, - core, g_chip_ident, chip); -} - const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -1018,7 +997,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, - .vidioc_g_chip_ident = vidioc_g_chip_ident, .vidioc_overlay = vidioc_overlay, .vidioc_g_fbuf = vidioc_g_fbuf, @@ -1039,7 +1017,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_g_chip_ident = vidioc_g_chip_ident, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 425aeadfb49..f953d33ee15 100644 --- a/drivers/media/common/siano/Kconfig +++ b/drivers/media/common/siano/Kconfig @@ -4,14 +4,30 @@ config SMS_SIANO_MDTV tristate - depends on DVB_CORE && RC_CORE && HAS_DMA + depends on DVB_CORE && HAS_DMA + depends on !RC_CORE || RC_CORE depends on SMS_USB_DRV || SMS_SDIO_DRV default y + +config SMS_SIANO_RC + bool "Enable Remote Controller support for Siano devices" + depends on SMS_SIANO_MDTV && RC_CORE + depends on SMS_USB_DRV || SMS_SDIO_DRV + depends on MEDIA_COMMON_OPTIONS + default y ---help--- - Choose Y or M here if you have MDTV receiver with a Siano chipset. + Choose Y to select Remote Controller support for Siano driver. - To compile this driver as a module, choose M here - (The module will be called smsmdtv). +config SMS_SIANO_DEBUGFS + bool "Enable debugfs for smsdvb" + depends on SMS_SIANO_MDTV + depends on DEBUG_FS + depends on SMS_USB_DRV + depends on CONFIG_SMS_USB_DRV = CONFIG_SMS_SDIO_DRV + + ---help--- + Choose Y to enable visualizing a dump of the frontend + statistics response packets via debugfs. Currently, works + only with Siano USB devices. - Further documentation on this driver can be found on the WWW - at http://www.siano-ms.com/ + Useful only for developers. In doubt, say N. diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile index 2a09279e064..4c0567f106b 100644 --- a/drivers/media/common/siano/Makefile +++ b/drivers/media/common/siano/Makefile @@ -1,7 +1,16 @@ -smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o +smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o +smsdvb-objs := smsdvb-main.o obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o +ifeq ($(CONFIG_SMS_SIANO_RC),y) + smsmdtv-objs += smsir.o +endif + +ifeq ($(CONFIG_SMS_SIANO_DEBUGFS),y) + smsdvb-objs += smsdvb-debugfs.o +endif + ccflags-y += -Idrivers/media/dvb-core ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 680c781c8dd..82769993eeb 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -28,43 +28,53 @@ MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); static struct sms_board sms_boards[] = { [SMS_BOARD_UNKNOWN] = { .name = "Unknown board", + .type = SMS_UNKNOWN_TYPE, + .default_mode = DEVICE_MODE_NONE, }, [SMS1XXX_BOARD_SIANO_STELLAR] = { .name = "Siano Stellar Digital Receiver", .type = SMS_STELLAR, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_NOVA_A] = { .name = "Siano Nova A Digital Receiver", .type = SMS_NOVA_A0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_NOVA_B] = { .name = "Siano Nova B Digital Receiver", .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_VEGA] = { .name = "Siano Vega Digital Receiver", .type = SMS_VEGA, + .default_mode = DEVICE_MODE_CMMB, }, [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { .name = "Hauppauge Catamount", .type = SMS_STELLAR, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_STELLAR, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { .name = "Hauppauge Okemo-A", .type = SMS_NOVA_A0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_A, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { .name = "Hauppauge Okemo-B", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_B, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_HCW_55XXX, + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, + .default_mode = DEVICE_MODE_DVBT_BDA, .rc_codes = RC_MAP_HAUPPAUGE, .board_cfg.leds_power = 26, .board_cfg.led0 = 27, @@ -77,7 +87,8 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, + .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = 29, .board_cfg.foreign_lna0_ctrl = 29, .rf_switch = 17, @@ -86,18 +97,65 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, + .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = -1, }, [SMS1XXX_BOARD_SIANO_NICE] = { - /* 11 */ .name = "Siano Nice Digital Receiver", .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_VENICE] = { - /* 12 */ .name = "Siano Venice Digital Receiver", .type = SMS_VEGA, + .default_mode = DEVICE_MODE_CMMB, + }, + [SMS1XXX_BOARD_SIANO_STELLAR_ROM] = { + .name = "Siano Stellar Digital Receiver ROM", + .type = SMS_STELLAR, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 1, + }, + [SMS1XXX_BOARD_ZTE_DVB_DATA_CARD] = { + .name = "ZTE Data Card Digital Receiver", + .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 5, + .mtu = 15792, + }, + [SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD] = { + .name = "ONDA Data Card Digital Receiver", + .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 6, + .mtu = 15792, + }, + [SMS1XXX_BOARD_SIANO_MING] = { + .name = "Siano Ming Digital Receiver", + .type = SMS_MING, + .default_mode = DEVICE_MODE_CMMB, + }, + [SMS1XXX_BOARD_SIANO_PELE] = { + .name = "Siano Pele Digital Receiver", + .type = SMS_PELE, + .default_mode = DEVICE_MODE_ISDBT_BDA, + }, + [SMS1XXX_BOARD_SIANO_RIO] = { + .name = "Siano Rio Digital Receiver", + .type = SMS_RIO, + .default_mode = DEVICE_MODE_ISDBT_BDA, + }, + [SMS1XXX_BOARD_SIANO_DENVER_1530] = { + .name = "Siano Denver (ATSC-M/H) Digital Receiver", + .type = SMS_DENVER_1530, + .default_mode = DEVICE_MODE_ATSC, + .crystal = 2400, + }, + [SMS1XXX_BOARD_SIANO_DENVER_2160] = { + .name = "Siano Denver (TDMB) Digital Receiver", + .type = SMS_DENVER_2160, + .default_mode = DEVICE_MODE_DAB_TDMB, }, }; @@ -109,20 +167,21 @@ struct sms_board *sms_get_board(unsigned id) } EXPORT_SYMBOL_GPL(sms_get_board); static inline void sms_gpio_assign_11xx_default_led_config( - struct smscore_gpio_config *pGpioConfig) { - pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; - pGpioConfig->InputCharacteristics = - SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; - pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; - pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; - pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; + struct smscore_config_gpio *p_gpio_config) { + p_gpio_config->direction = SMS_GPIO_DIRECTION_OUTPUT; + p_gpio_config->inputcharacteristics = + SMS_GPIO_INPUTCHARACTERISTICS_NORMAL; + p_gpio_config->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA; + p_gpio_config->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + p_gpio_config->pullupdown = SMS_GPIO_PULLUPDOWN_NONE; } int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent) { - struct smscore_gpio_config MyGpioConfig; + enum SMS_BOARD_EVENTS gevent) +{ + struct smscore_config_gpio my_gpio_config; - sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + sms_gpio_assign_11xx_default_led_config(&my_gpio_config); switch (gevent) { case BOARD_EVENT_POWER_INIT: /* including hotplug */ @@ -182,8 +241,8 @@ static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) .direction = SMS_GPIO_DIRECTION_OUTPUT, .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, - .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, - .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + .outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_FAST, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA, }; if (pin == 0) @@ -293,19 +352,7 @@ EXPORT_SYMBOL_GPL(sms_board_lna_control); int sms_board_load_modules(int id) { - switch (id) { - case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - request_module("smsdvb"); - break; - default: - /* do nothing */ - break; - } + request_module("smsdvb"); return 0; } EXPORT_SYMBOL_GPL(sms_board_load_modules); diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index d8cdf756f7c..c63b544c49c 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -37,6 +37,14 @@ #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 #define SMS1XXX_BOARD_SIANO_NICE 11 #define SMS1XXX_BOARD_SIANO_VENICE 12 +#define SMS1XXX_BOARD_SIANO_STELLAR_ROM 13 +#define SMS1XXX_BOARD_ZTE_DVB_DATA_CARD 14 +#define SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD 15 +#define SMS1XXX_BOARD_SIANO_MING 16 +#define SMS1XXX_BOARD_SIANO_PELE 17 +#define SMS1XXX_BOARD_SIANO_RIO 18 +#define SMS1XXX_BOARD_SIANO_DENVER_1530 19 +#define SMS1XXX_BOARD_SIANO_DENVER_2160 20 struct sms_board_gpio_cfg { int lna_vhf_exist; @@ -79,6 +87,12 @@ struct sms_board { /* gpios */ int led_power, led_hi, led_lo, lna_ctrl, rf_switch; + + char intf_num; + int default_mode; + unsigned int mtu; + unsigned int crystal; + struct sms_antenna_config_ST *antenna_config; }; struct sms_board *sms_get_board(unsigned id); diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9cc55546cc3..050984c5b1e 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -37,7 +37,6 @@ #include "smscoreapi.h" #include "sms-cards.h" #include "smsir.h" -#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -58,11 +57,350 @@ struct smscore_client_t { struct list_head entry; struct smscore_device_t *coredev; void *context; - struct list_head idlist; - onresponse_t onresponse_handler; + struct list_head idlist; + onresponse_t onresponse_handler; onremove_t onremove_handler; }; +static char *siano_msgs[] = { + [MSG_TYPE_BASE_VAL - MSG_TYPE_BASE_VAL] = "MSG_TYPE_BASE_VAL", + [MSG_SMS_GET_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_REQ", + [MSG_SMS_GET_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_RES", + [MSG_SMS_MULTI_BRIDGE_CFG - MSG_TYPE_BASE_VAL] = "MSG_SMS_MULTI_BRIDGE_CFG", + [MSG_SMS_GPIO_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_REQ", + [MSG_SMS_GPIO_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_RES", + [MSG_SMS_GPIO_SET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_REQ", + [MSG_SMS_GPIO_SET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_RES", + [MSG_SMS_GPIO_GET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_REQ", + [MSG_SMS_GPIO_GET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_RES", + [MSG_SMS_EEPROM_BURN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_BURN_IND", + [MSG_SMS_LOG_ENABLE_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_REQ", + [MSG_SMS_LOG_ENABLE_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_RES", + [MSG_SMS_SET_MAX_TX_MSG_LEN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_REQ", + [MSG_SMS_SET_MAX_TX_MSG_LEN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_RES", + [MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE", + [MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST", + [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ", + [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES", + [MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND", + [MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND", + [MSG_SMS_CONFIGURE_RF_SWITCH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_REQ", + [MSG_SMS_CONFIGURE_RF_SWITCH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_RES", + [MSG_SMS_MRC_PATH_DISCONNECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_REQ", + [MSG_SMS_MRC_PATH_DISCONNECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_RES", + [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ", + [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES", + [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ", + [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES", + [MSG_WR_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_REQ", + [MSG_WR_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_RES", + [MSG_RD_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_REQ", + [MSG_RD_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_RES", + [MSG_RD_REG_ALL_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_REQ", + [MSG_RD_REG_ALL_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_RES", + [MSG_HELP_INT - MSG_TYPE_BASE_VAL] = "MSG_HELP_INT", + [MSG_RUN_SCRIPT_INT - MSG_TYPE_BASE_VAL] = "MSG_RUN_SCRIPT_INT", + [MSG_SMS_EWS_INBAND_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_REQ", + [MSG_SMS_EWS_INBAND_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_RES", + [MSG_SMS_RFS_SELECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_REQ", + [MSG_SMS_RFS_SELECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_RES", + [MSG_SMS_MB_GET_VER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_REQ", + [MSG_SMS_MB_GET_VER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_RES", + [MSG_SMS_MB_WRITE_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_REQ", + [MSG_SMS_MB_WRITE_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_RES", + [MSG_SMS_MB_READ_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_REQ", + [MSG_SMS_MB_READ_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_RES", + [MSG_SMS_RD_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_REQ", + [MSG_SMS_RD_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_RES", + [MSG_SMS_WR_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_REQ", + [MSG_SMS_WR_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_RES", + [MSG_SMS_UPDATE_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_REQ", + [MSG_SMS_UPDATE_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_RES", + [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ", + [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES", + [MSG_SMS_RF_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_REQ", + [MSG_SMS_RF_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_RES", + [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ", + [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES", + [MSG_SMS_ISDBT_SB_RECEPTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_REQ", + [MSG_SMS_ISDBT_SB_RECEPTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_RES", + [MSG_SMS_GENERIC_EPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_REQ", + [MSG_SMS_GENERIC_EPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_RES", + [MSG_SMS_GENERIC_EPROM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_REQ", + [MSG_SMS_GENERIC_EPROM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_RES", + [MSG_SMS_EEPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_REQ", + [MSG_SMS_EEPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_RES", + [MSG_SMS_CUSTOM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_REQ", + [MSG_SMS_CUSTOM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_RES", + [MSG_SMS_CUSTOM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_REQ", + [MSG_SMS_CUSTOM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_RES", + [MSG_SMS_INIT_DEVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_REQ", + [MSG_SMS_INIT_DEVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_RES", + [MSG_SMS_ATSC_SET_ALL_IP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_REQ", + [MSG_SMS_ATSC_SET_ALL_IP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_RES", + [MSG_SMS_ATSC_START_ENSEMBLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_REQ", + [MSG_SMS_ATSC_START_ENSEMBLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_RES", + [MSG_SMS_SET_OUTPUT_MODE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_REQ", + [MSG_SMS_SET_OUTPUT_MODE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_RES", + [MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ", + [MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES", + [MSG_SMS_SUB_CHANNEL_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_REQ", + [MSG_SMS_SUB_CHANNEL_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_RES", + [MSG_SMS_SUB_CHANNEL_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_REQ", + [MSG_SMS_SUB_CHANNEL_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_RES", + [MSG_SMS_ATSC_IP_FILTER_ADD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_REQ", + [MSG_SMS_ATSC_IP_FILTER_ADD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_RES", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_RES", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES", + [MSG_SMS_WAIT_CMD - MSG_TYPE_BASE_VAL] = "MSG_SMS_WAIT_CMD", + [MSG_SMS_ADD_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_REQ", + [MSG_SMS_ADD_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_RES", + [MSG_SMS_REMOVE_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_REQ", + [MSG_SMS_REMOVE_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_RES", + [MSG_SMS_FAST_INFORMATION_CHANNEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_REQ", + [MSG_SMS_FAST_INFORMATION_CHANNEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_RES", + [MSG_SMS_DAB_CHANNEL - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_CHANNEL", + [MSG_SMS_GET_PID_FILTER_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_REQ", + [MSG_SMS_GET_PID_FILTER_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_RES", + [MSG_SMS_POWER_DOWN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_REQ", + [MSG_SMS_POWER_DOWN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_RES", + [MSG_SMS_ATSC_SLT_EXIST_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SLT_EXIST_IND", + [MSG_SMS_ATSC_NO_SLT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_NO_SLT_IND", + [MSG_SMS_GET_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_REQ", + [MSG_SMS_GET_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_RES", + [MSG_SMS_SEND_DUMP - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_DUMP", + [MSG_SMS_SCAN_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_REQ", + [MSG_SMS_SCAN_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_RES", + [MSG_SMS_SCAN_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_REQ", + [MSG_SMS_SCAN_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_RES", + [MSG_SMS_SCAN_PROGRESS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_PROGRESS_IND", + [MSG_SMS_SCAN_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_COMPLETE_IND", + [MSG_SMS_LOG_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ITEM", + [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ", + [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES", + [MSG_SMS_HO_PER_SLICES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PER_SLICES_IND", + [MSG_SMS_HO_INBAND_POWER_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_INBAND_POWER_IND", + [MSG_SMS_MANUAL_DEMOD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MANUAL_DEMOD_REQ", + [MSG_SMS_HO_TUNE_ON_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_REQ", + [MSG_SMS_HO_TUNE_ON_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_RES", + [MSG_SMS_HO_TUNE_OFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_REQ", + [MSG_SMS_HO_TUNE_OFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_RES", + [MSG_SMS_HO_PEEK_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_REQ", + [MSG_SMS_HO_PEEK_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_RES", + [MSG_SMS_HO_PEEK_FREQ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_IND", + [MSG_SMS_MB_ATTEN_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_REQ", + [MSG_SMS_MB_ATTEN_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_RES", + [MSG_SMS_ENABLE_STAT_IN_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_REQ", + [MSG_SMS_ENABLE_STAT_IN_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_RES", + [MSG_SMS_SET_ANTENNA_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_REQ", + [MSG_SMS_SET_ANTENNA_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_RES", + [MSG_SMS_GET_STATISTICS_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_REQ", + [MSG_SMS_GET_STATISTICS_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_RES", + [MSG_SMS_SLEEP_RESUME_COMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLEEP_RESUME_COMP_IND", + [MSG_SMS_SWITCH_HOST_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_REQ", + [MSG_SMS_SWITCH_HOST_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_RES", + [MSG_SMS_DATA_DOWNLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_REQ", + [MSG_SMS_DATA_DOWNLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_RES", + [MSG_SMS_DATA_VALIDITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_REQ", + [MSG_SMS_DATA_VALIDITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_RES", + [MSG_SMS_SWDOWNLOAD_TRIGGER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_REQ", + [MSG_SMS_SWDOWNLOAD_TRIGGER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_RES", + [MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ", + [MSG_SMS_SWDOWNLOAD_BACKDOOR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_RES", + [MSG_SMS_GET_VERSION_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_REQ", + [MSG_SMS_GET_VERSION_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_RES", + [MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ", + [MSG_SMS_CLOCK_OUTPUT_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_RES", + [MSG_SMS_I2C_SET_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_REQ", + [MSG_SMS_I2C_SET_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_RES", + [MSG_SMS_GENERIC_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_REQ", + [MSG_SMS_GENERIC_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_RES", + [MSG_SMS_DVBT_BDA_DATA - MSG_TYPE_BASE_VAL] = "MSG_SMS_DVBT_BDA_DATA", + [MSG_SW_RELOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_REQ", + [MSG_SMS_DATA_MSG - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_MSG", + [MSG_TABLE_UPLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_REQ", + [MSG_TABLE_UPLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_RES", + [MSG_SW_RELOAD_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_REQ", + [MSG_SW_RELOAD_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_RES", + [MSG_SW_RELOAD_EXEC_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_REQ", + [MSG_SW_RELOAD_EXEC_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_RES", + [MSG_SMS_SPI_INT_LINE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_REQ", + [MSG_SMS_SPI_INT_LINE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_RES", + [MSG_SMS_GPIO_CONFIG_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_REQ", + [MSG_SMS_GPIO_CONFIG_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_RES", + [MSG_SMS_WATCHDOG_ACT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_REQ", + [MSG_SMS_WATCHDOG_ACT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_RES", + [MSG_SMS_LOOPBACK_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_REQ", + [MSG_SMS_LOOPBACK_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_RES", + [MSG_SMS_RAW_CAPTURE_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_REQ", + [MSG_SMS_RAW_CAPTURE_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_RES", + [MSG_SMS_RAW_CAPTURE_ABORT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_REQ", + [MSG_SMS_RAW_CAPTURE_ABORT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_RES", + [MSG_SMS_RAW_CAPTURE_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_COMPLETE_IND", + [MSG_SMS_DATA_PUMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_IND", + [MSG_SMS_DATA_PUMP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_REQ", + [MSG_SMS_DATA_PUMP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_RES", + [MSG_SMS_FLASH_DL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FLASH_DL_REQ", + [MSG_SMS_EXEC_TEST_1_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_REQ", + [MSG_SMS_EXEC_TEST_1_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_RES", + [MSG_SMS_ENBALE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_REQ", + [MSG_SMS_ENBALE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_RES", + [MSG_SMS_SPI_SET_BUS_WIDTH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_REQ", + [MSG_SMS_SPI_SET_BUS_WIDTH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_RES", + [MSG_SMS_SEND_EMM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_REQ", + [MSG_SMS_SEND_EMM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_RES", + [MSG_SMS_DISABLE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_REQ", + [MSG_SMS_DISABLE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_RES", + [MSG_SMS_IS_BUF_FREE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_REQ", + [MSG_SMS_IS_BUF_FREE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_RES", + [MSG_SMS_EXT_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_REQ", + [MSG_SMS_EXT_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_RES", + [MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE", + [MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE", + [MSG_SMS_BATTERY_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_REQ", + [MSG_SMS_BATTERY_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_RES", + [MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE", + [MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE", + [MSG_SMS_FM_RADIO_BLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_FM_RADIO_BLOCK_IND", + [MSG_SMS_HOST_NOTIFICATION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HOST_NOTIFICATION_IND", + [MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE", + [MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE", + [MSG_SMS_CMMB_GET_NETWORKS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_REQ", + [MSG_SMS_CMMB_GET_NETWORKS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_RES", + [MSG_SMS_CMMB_START_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_REQ", + [MSG_SMS_CMMB_START_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_RES", + [MSG_SMS_CMMB_STOP_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_REQ", + [MSG_SMS_CMMB_STOP_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_RES", + [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ", + [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES", + [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ", + [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES", + [MSG_SMS_CMMB_START_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_REQ", + [MSG_SMS_CMMB_START_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_RES", + [MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ", + [MSG_SMS_CMMB_STOP_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_RES", + [MSG_SMS_ISDBT_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_REQ", + [MSG_SMS_ISDBT_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_RES", + [MSG_SMS_TRANSMISSION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_TRANSMISSION_IND", + [MSG_SMS_PID_STATISTICS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_PID_STATISTICS_IND", + [MSG_SMS_POWER_DOWN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_IND", + [MSG_SMS_POWER_DOWN_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_CONF", + [MSG_SMS_POWER_UP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_IND", + [MSG_SMS_POWER_UP_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_CONF", + [MSG_SMS_POWER_MODE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_REQ", + [MSG_SMS_POWER_MODE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_RES", + [MSG_SMS_DEBUG_HOST_EVENT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_REQ", + [MSG_SMS_DEBUG_HOST_EVENT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_RES", + [MSG_SMS_NEW_CRYSTAL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_REQ", + [MSG_SMS_NEW_CRYSTAL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_RES", + [MSG_SMS_CONFIG_SPI_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_REQ", + [MSG_SMS_CONFIG_SPI_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_RES", + [MSG_SMS_I2C_SHORT_STAT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SHORT_STAT_IND", + [MSG_SMS_START_IR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_REQ", + [MSG_SMS_START_IR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_RES", + [MSG_SMS_IR_SAMPLES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_IR_SAMPLES_IND", + [MSG_SMS_CMMB_CA_SERVICE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_CA_SERVICE_IND", + [MSG_SMS_SLAVE_DEVICE_DETECTED - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLAVE_DEVICE_DETECTED", + [MSG_SMS_INTERFACE_LOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_LOCK_IND", + [MSG_SMS_INTERFACE_UNLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_UNLOCK_IND", + [MSG_SMS_SEND_ROSUM_BUFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_REQ", + [MSG_SMS_SEND_ROSUM_BUFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_RES", + [MSG_SMS_ROSUM_BUFF - MSG_TYPE_BASE_VAL] = "MSG_SMS_ROSUM_BUFF", + [MSG_SMS_SET_AES128_KEY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_REQ", + [MSG_SMS_SET_AES128_KEY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_RES", + [MSG_SMS_MBBMS_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_REQ", + [MSG_SMS_MBBMS_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_RES", + [MSG_SMS_MBBMS_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_READ_IND", + [MSG_SMS_IQ_STREAM_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_REQ", + [MSG_SMS_IQ_STREAM_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_RES", + [MSG_SMS_IQ_STREAM_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_REQ", + [MSG_SMS_IQ_STREAM_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_RES", + [MSG_SMS_IQ_STREAM_DATA_BLOCK - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_DATA_BLOCK", + [MSG_SMS_GET_EEPROM_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_REQ", + [MSG_SMS_GET_EEPROM_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_RES", + [MSG_SMS_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SIGNAL_DETECTED_IND", + [MSG_SMS_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_NO_SIGNAL_IND", + [MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ", + [MSG_SMS_MRC_SHUTDOWN_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_RES", + [MSG_SMS_MRC_BRINGUP_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_REQ", + [MSG_SMS_MRC_BRINGUP_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_RES", + [MSG_SMS_EXTERNAL_LNA_CTRL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_REQ", + [MSG_SMS_EXTERNAL_LNA_CTRL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_RES", + [MSG_SMS_SET_PERIODIC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_REQ", + [MSG_SMS_SET_PERIODIC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_RES", + [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ", + [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES", + [LOCAL_TUNE - MSG_TYPE_BASE_VAL] = "LOCAL_TUNE", + [LOCAL_IFFT_H_ICI - MSG_TYPE_BASE_VAL] = "LOCAL_IFFT_H_ICI", + [MSG_RESYNC_REQ - MSG_TYPE_BASE_VAL] = "MSG_RESYNC_REQ", + [MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ", + [MSG_SMS_CMMB_GET_MRC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_RES", + [MSG_SMS_LOG_EX_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_EX_ITEM", + [MSG_SMS_DEVICE_DATA_LOSS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEVICE_DATA_LOSS_IND", + [MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND", + [MSG_SMS_USER_MSG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_REQ", + [MSG_SMS_USER_MSG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_RES", + [MSG_SMS_SMART_CARD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_REQ", + [MSG_SMS_SMART_CARD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_RES", + [MSG_SMS_SMART_CARD_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_REQ", + [MSG_SMS_SMART_CARD_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_RES", + [MSG_SMS_SMART_CARD_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_READ_IND", + [MSG_SMS_TSE_ENABLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_REQ", + [MSG_SMS_TSE_ENABLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_RES", + [MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ", + [MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES", + [MSG_SMS_LED_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_REQ", + [MSG_SMS_LED_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_RES", + [MSG_PWM_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_REQ", + [MSG_PWM_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_RES", + [MSG_SMS_CMMB_SMD_SN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_REQ", + [MSG_SMS_CMMB_SMD_SN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_RES", + [MSG_SMS_CMMB_SET_CA_CW_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_REQ", + [MSG_SMS_CMMB_SET_CA_CW_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_RES", + [MSG_SMS_CMMB_SET_CA_SALT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_REQ", + [MSG_SMS_CMMB_SET_CA_SALT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_RES", + [MSG_SMS_NSCD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_REQ", + [MSG_SMS_NSCD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_RES", + [MSG_SMS_NSCD_PROCESS_SECTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_REQ", + [MSG_SMS_NSCD_PROCESS_SECTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_RES", + [MSG_SMS_DBD_CREATE_OBJECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_REQ", + [MSG_SMS_DBD_CREATE_OBJECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_RES", + [MSG_SMS_DBD_CONFIGURE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_REQ", + [MSG_SMS_DBD_CONFIGURE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_RES", + [MSG_SMS_DBD_SET_KEYS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_REQ", + [MSG_SMS_DBD_SET_KEYS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_RES", + [MSG_SMS_DBD_PROCESS_HEADER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_REQ", + [MSG_SMS_DBD_PROCESS_HEADER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_RES", + [MSG_SMS_DBD_PROCESS_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_REQ", + [MSG_SMS_DBD_PROCESS_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_RES", + [MSG_SMS_DBD_PROCESS_GET_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_REQ", + [MSG_SMS_DBD_PROCESS_GET_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_RES", + [MSG_SMS_NSCD_OPEN_SESSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_REQ", + [MSG_SMS_NSCD_OPEN_SESSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_RES", + [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ", + [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES", + [MSG_LAST_MSG_TYPE - MSG_TYPE_BASE_VAL] = "MSG_LAST_MSG_TYPE", +}; + +char *smscore_translate_msg(enum msg_types msgtype) +{ + int i = msgtype - MSG_TYPE_BASE_VAL; + char *msg; + + if (i < 0 || i >= ARRAY_SIZE(siano_msgs)) + return "Unknown msg type"; + + msg = siano_msgs[i]; + + if (!*msg) + return "Unknown msg type"; + + return msg; +} +EXPORT_SYMBOL_GPL(smscore_translate_msg); + void smscore_set_board_id(struct smscore_device_t *core, int id) { core->board_id = id; @@ -96,7 +434,7 @@ static struct mutex g_smscore_deviceslock; static struct list_head g_smscore_registry; static struct mutex g_smscore_registrylock; -static int default_mode = 4; +static int default_mode = DEVICE_MODE_NONE; module_param(default_mode, int, 0644); MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); @@ -151,10 +489,10 @@ static enum sms_device_type_st smscore_registry_gettype(char *devpath) else sms_err("No registry found."); - return -1; + return -EINVAL; } -void smscore_registry_setmode(char *devpath, int mode) +static void smscore_registry_setmode(char *devpath, int mode) { struct smscore_registry_entry_t *entry; @@ -294,10 +632,11 @@ static struct smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, dma_addr_t common_buffer_phys) { - struct smscore_buffer_t *cb = - kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + struct smscore_buffer_t *cb; + + cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); if (!cb) { - sms_info("kmalloc(...) failed"); + sms_info("kzalloc(...) failed"); return NULL; } @@ -344,6 +683,7 @@ int smscore_register_device(struct smsdevice_params_t *params, /* init completion events */ init_completion(&dev->version_ex_done); init_completion(&dev->data_download_done); + init_completion(&dev->data_validity_done); init_completion(&dev->trigger_done); init_completion(&dev->init_device_done); init_completion(&dev->reload_start_done); @@ -370,9 +710,10 @@ int smscore_register_device(struct smsdevice_params_t *params, for (buffer = dev->common_buffer; dev->num_buffers < params->num_buffers; dev->num_buffers++, buffer += params->buffer_size) { - struct smscore_buffer_t *cb = - smscore_createbuffer(buffer, dev->common_buffer, - dev->common_buffer_phys); + struct smscore_buffer_t *cb; + + cb = smscore_createbuffer(buffer, dev->common_buffer, + dev->common_buffer_phys); if (!cb) { smscore_unregister_device(dev); return -ENOMEM; @@ -384,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params, sms_info("allocated %d buffers", dev->num_buffers); dev->mode = DEVICE_MODE_NONE; + dev->board_id = SMS_BOARD_UNKNOWN; dev->context = params->context; dev->device = params->device; dev->setmode_handler = params->setmode_handler; @@ -413,7 +755,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device); static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer, size_t size, struct completion *completion) { - int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + int rc; + + if (completion == NULL) + return -EINVAL; + init_completion(completion); + + rc = coredev->sendrequest_handler(coredev->context, buffer, size); if (rc < 0) { sms_info("sendrequest returned error %d", rc); return rc; @@ -444,24 +792,22 @@ static int smscore_init_ir(struct smscore_device_t *coredev) if (rc != 0) sms_err("Error initialization DTV IR sub-module"); else { - buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + buffer = kmalloc(sizeof(struct sms_msg_data2) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (buffer) { - struct SmsMsgData_ST2 *msg = - (struct SmsMsgData_ST2 *) + struct sms_msg_data2 *msg = + (struct sms_msg_data2 *) SMS_ALIGN_ADDRESS(buffer); - SMS_INIT_MSG(&msg->xMsgHeader, + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_START_IR_REQ, - sizeof(struct SmsMsgData_ST2)); - msg->msgData[0] = coredev->ir.controller; - msg->msgData[1] = coredev->ir.timeout; + sizeof(struct sms_msg_data2)); + msg->msg_data[0] = coredev->ir.controller; + msg->msg_data[1] = coredev->ir.timeout; - smsendian_handle_tx_message( - (struct SmsMsgHdr_ST2 *)msg); rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader. msgLength, + msg->x_msg_header. msg_length, &coredev->ir_init_done); kfree(buffer); @@ -476,21 +822,82 @@ static int smscore_init_ir(struct smscore_device_t *coredev) } /** + * configures device features according to board configuration structure. + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +static int smscore_configure_board(struct smscore_device_t *coredev) +{ + struct sms_board *board; + + board = sms_get_board(coredev->board_id); + if (!board) { + sms_err("no board configuration exist."); + return -EINVAL; + } + + if (board->mtu) { + struct sms_msg_data mtu_msg; + sms_debug("set max transmit unit %d", board->mtu); + + mtu_msg.x_msg_header.msg_src_id = 0; + mtu_msg.x_msg_header.msg_dst_id = HIF_TASK; + mtu_msg.x_msg_header.msg_flags = 0; + mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; + mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg); + mtu_msg.msg_data[0] = board->mtu; + + coredev->sendrequest_handler(coredev->context, &mtu_msg, + sizeof(mtu_msg)); + } + + if (board->crystal) { + struct sms_msg_data crys_msg; + sms_debug("set crystal value %d", board->crystal); + + SMS_INIT_MSG(&crys_msg.x_msg_header, + MSG_SMS_NEW_CRYSTAL_REQ, + sizeof(crys_msg)); + crys_msg.msg_data[0] = board->crystal; + + coredev->sendrequest_handler(coredev->context, &crys_msg, + sizeof(crys_msg)); + } + + return 0; +} + +/** * sets initial device mode and notifies client hotplugs that device is ready * * @param coredev pointer to a coredev object returned by - * smscore_register_device + * smscore_register_device * * @return 0 on success, <0 on error. */ int smscore_start_device(struct smscore_device_t *coredev) { - int rc = smscore_set_device_mode( - coredev, smscore_registry_getmode(coredev->devpath)); + int rc; + int board_id = smscore_get_board_id(coredev); + int mode = smscore_registry_getmode(coredev->devpath); + + /* Device is initialized as DEVICE_MODE_NONE */ + if (board_id != SMS_BOARD_UNKNOWN && mode == DEVICE_MODE_NONE) + mode = sms_get_board(board_id)->default_mode; + + rc = smscore_set_device_mode(coredev, mode); if (rc < 0) { sms_info("set device mode faile , rc %d", rc); return rc; } + rc = smscore_configure_board(coredev); + if (rc < 0) { + sms_info("configure board failed , rc %d", rc); + return rc; + } kmutex_lock(&g_smscore_deviceslock); @@ -509,18 +916,19 @@ EXPORT_SYMBOL_GPL(smscore_start_device); static int smscore_load_firmware_family2(struct smscore_device_t *coredev, void *buffer, size_t size) { - struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgHdr_ST *msg; - u32 mem_address; - u8 *payload = firmware->Payload; + struct sms_firmware *firmware = (struct sms_firmware *) buffer; + struct sms_msg_data4 *msg; + u32 mem_address, calc_checksum = 0; + u32 i, *ptr; + u8 *payload = firmware->payload; int rc = 0; - firmware->StartAddress = le32_to_cpu(firmware->StartAddress); - firmware->Length = le32_to_cpu(firmware->Length); + firmware->start_address = le32_to_cpup((__le32 *)&firmware->start_address); + firmware->length = le32_to_cpup((__le32 *)&firmware->length); - mem_address = firmware->StartAddress; + mem_address = firmware->start_address; sms_info("loading FW to addr 0x%x size %d", - mem_address, firmware->Length); + mem_address, firmware->length); if (coredev->preload_handler) { rc = coredev->preload_handler(coredev->context); if (rc < 0) @@ -534,35 +942,36 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, if (coredev->mode != DEVICE_MODE_NONE) { sms_debug("sending reload command."); - SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, - sizeof(struct SmsMsgHdr_ST)); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ, + sizeof(struct sms_msg_hdr)); rc = smscore_sendrequest_and_wait(coredev, msg, - msg->msgLength, + msg->x_msg_header.msg_length, &coredev->reload_start_done); + if (rc < 0) { + sms_err("device reload failed, rc %d", rc); + goto exit_fw_download; + } mem_address = *(u32 *) &payload[20]; } + for (i = 0, ptr = (u32 *)firmware->payload; i < firmware->length/4 ; + i++, ptr++) + calc_checksum += *ptr; + while (size && rc >= 0) { - struct SmsDataDownload_ST *DataMsg = - (struct SmsDataDownload_ST *) msg; - int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); + struct sms_data_download *data_msg = + (struct sms_data_download *) msg; + int payload_size = min_t(int, size, SMS_MAX_PAYLOAD_SIZE); - SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, - (u16)(sizeof(struct SmsMsgHdr_ST) + + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_DOWNLOAD_REQ, + (u16)(sizeof(struct sms_msg_hdr) + sizeof(u32) + payload_size)); - DataMsg->MemAddr = mem_address; - memcpy(DataMsg->Payload, payload, payload_size); + data_msg->mem_addr = mem_address; + memcpy(data_msg->payload, payload, payload_size); - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && - (coredev->mode == DEVICE_MODE_NONE)) - rc = coredev->sendrequest_handler( - coredev->context, DataMsg, - DataMsg->xMsgHeader.msgLength); - else - rc = smscore_sendrequest_and_wait( - coredev, DataMsg, - DataMsg->xMsgHeader.msgLength, + rc = smscore_sendrequest_and_wait(coredev, data_msg, + data_msg->x_msg_header.msg_length, &coredev->data_download_done); payload += payload_size; @@ -570,50 +979,158 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, mem_address += payload_size; } - if (rc >= 0) { - if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; - - SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) * 5); - - TriggerMsg->msgData[0] = firmware->StartAddress; - /* Entry point */ - TriggerMsg->msgData[1] = 5; /* Priority */ - TriggerMsg->msgData[2] = 0x200; /* Stack size */ - TriggerMsg->msgData[3] = 0; /* Parameter */ - TriggerMsg->msgData[4] = 4; /* Task ID */ - - if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { - rc = coredev->sendrequest_handler( - coredev->context, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength); - msleep(100); - } else - rc = smscore_sendrequest_and_wait( - coredev, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength, + if (rc < 0) + goto exit_fw_download; + + sms_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x", + calc_checksum); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ, + sizeof(msg->x_msg_header) + + sizeof(u32) * 3); + msg->msg_data[0] = firmware->start_address; + /* Entry point */ + msg->msg_data[1] = firmware->length; + msg->msg_data[2] = 0; /* Regular checksum*/ + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->x_msg_header.msg_length, + &coredev->data_validity_done); + if (rc < 0) + goto exit_fw_download; + + if (coredev->mode == DEVICE_MODE_NONE) { + struct sms_msg_data *trigger_msg = + (struct sms_msg_data *) msg; + + sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); + SMS_INIT_MSG(&msg->x_msg_header, + MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct sms_msg_hdr) + + sizeof(u32) * 5); + + trigger_msg->msg_data[0] = firmware->start_address; + /* Entry point */ + trigger_msg->msg_data[1] = 6; /* Priority */ + trigger_msg->msg_data[2] = 0x200; /* Stack size */ + trigger_msg->msg_data[3] = 0; /* Parameter */ + trigger_msg->msg_data[4] = 4; /* Task ID */ + + rc = smscore_sendrequest_and_wait(coredev, trigger_msg, + trigger_msg->x_msg_header.msg_length, &coredev->trigger_done); - } else { - SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = coredev->sendrequest_handler(coredev->context, - msg, msg->msgLength); - } - msleep(500); + } else { + SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct sms_msg_hdr)); + rc = coredev->sendrequest_handler(coredev->context, msg, + msg->x_msg_header.msg_length); } - sms_debug("rc=%d, postload=%p ", rc, - coredev->postload_handler); + if (rc < 0) + goto exit_fw_download; + /* + * backward compatibility - wait to device_ready_done for + * not more than 400 ms + */ + msleep(400); + +exit_fw_download: kfree(msg); - return ((rc >= 0) && coredev->postload_handler) ? - coredev->postload_handler(coredev->context) : - rc; + if (coredev->postload_handler) { + sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler); + if (rc >= 0) + return coredev->postload_handler(coredev->context); + } + + sms_debug("rc=%d", rc); + return rc; +} + +static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { + [SMS_NOVA_A0] = { + [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ, + }, + [SMS_NOVA_B0] = { + [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ_B0, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ_B0, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ_B0, + [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO, + [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO, + }, + [SMS_VEGA] = { + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VEGA_12MHZ, + }, + [SMS_VENICE] = { + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VENICE_12MHZ, + }, + [SMS_MING] = { + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_MING_APP, + }, + [SMS_PELE] = { + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_PELE, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_PELE, + }, + [SMS_RIO] = { + [DEVICE_MODE_DVBT] = SMS_FW_DVB_RIO, + [DEVICE_MODE_DVBH] = SMS_FW_DVBH_RIO, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_RIO, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_RIO, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_RIO, + [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO_RIO, + [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO_RIO, + }, + [SMS_DENVER_1530] = { + [DEVICE_MODE_ATSC] = SMS_FW_ATSC_DENVER, + }, + [SMS_DENVER_2160] = { + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_DENVER, + }, +}; + +/** + * get firmware file name from one of the two mechanisms : sms_boards or + * smscore_fw_lkup. + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * @param lookup if 1, always get the fw filename from smscore_fw_lkup + * table. if 0, try first to get from sms_boards + * + * @return 0 on success, <0 on error. + */ +static char *smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode) +{ + char **fw; + int board_id = smscore_get_board_id(coredev); + enum sms_device_type_st type; + + type = smscore_registry_gettype(coredev->devpath); + + /* Prevent looking outside the smscore_fw_lkup table */ + if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES) + return NULL; + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) + return NULL; + + sms_debug("trying to get fw name from sms_boards board_id %d mode %d", + board_id, mode); + fw = sms_get_board(board_id)->fw; + if (!fw || !fw[mode]) { + sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", + mode, type); + return smscore_fw_lkup[type][mode]; + } + + return fw[mode]; } /** @@ -627,41 +1144,47 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, * @return 0 on success, <0 on error. */ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, - char *filename, + int mode, loadfirmware_t loadfirmware_handler) { int rc = -ENOENT; + u8 *fw_buf; + u32 fw_buf_size; const struct firmware *fw; - u8 *fw_buffer; - if (loadfirmware_handler == NULL && !(coredev->device_flags & - SMS_DEVICE_FAMILY2)) + char *fw_filename = smscore_get_fw_filename(coredev, mode); + if (!fw_filename) { + sms_err("mode %d not supported on this device", mode); + return -ENOENT; + } + sms_debug("Firmware name: %s", fw_filename); + + if (loadfirmware_handler == NULL && !(coredev->device_flags + & SMS_DEVICE_FAMILY2)) return -EINVAL; - rc = request_firmware(&fw, filename, coredev->device); + rc = request_firmware(&fw, fw_filename, coredev->device); if (rc < 0) { - sms_info("failed to open \"%s\"", filename); + sms_err("failed to open firmware file \"%s\"", fw_filename); return rc; } - sms_info("read FW %s, size=%zd", filename, fw->size); - fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), - GFP_KERNEL | GFP_DMA); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); + sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size); + fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (!fw_buf) { + sms_err("failed to allocate firmware buffer"); + rc = -ENOMEM; + } else { + memcpy(fw_buf, fw->data, fw->size); + fw_buf_size = fw->size; rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? - smscore_load_firmware_family2(coredev, - fw_buffer, - fw->size) : - loadfirmware_handler(coredev->context, - fw_buffer, fw->size); - - kfree(fw_buffer); - } else { - sms_info("failed to allocate firmware buffer"); - rc = -ENOMEM; + smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size) + : loadfirmware_handler(coredev->context, fw_buf, + fw_buf_size); } + kfree(fw_buf); release_firmware(fw); return rc; @@ -703,14 +1226,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev) if (num_buffers == coredev->num_buffers) break; if (++retry > 10) { - sms_info("exiting although " - "not all buffers released."); + sms_info("exiting although not all buffers released."); break; } sms_info("waiting for %d buffer(s)", coredev->num_buffers - num_buffers); + kmutex_unlock(&g_smscore_deviceslock); msleep(100); + kmutex_lock(&g_smscore_deviceslock); } sms_info("freed %d buffers", num_buffers); @@ -719,8 +1243,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) dma_free_coherent(NULL, coredev->common_buffer_size, coredev->common_buffer, coredev->common_buffer_phys); - if (coredev->fw_buf != NULL) - kfree(coredev->fw_buf); + kfree(coredev->fw_buf); list_del(&coredev->entry); kfree(coredev); @@ -733,19 +1256,19 @@ EXPORT_SYMBOL_GPL(smscore_unregister_device); static int smscore_detect_mode(struct smscore_device_t *coredev) { - void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, + void *buffer = kmalloc(sizeof(struct sms_msg_hdr) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - struct SmsMsgHdr_ST *msg = - (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); + struct sms_msg_hdr *msg = + (struct sms_msg_hdr *) SMS_ALIGN_ADDRESS(buffer); int rc; if (!buffer) return -ENOMEM; SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, - sizeof(struct SmsMsgHdr_ST)); + sizeof(struct sms_msg_hdr)); - rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, + rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc == -ETIME) { sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); @@ -753,11 +1276,11 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) if (wait_for_completion_timeout(&coredev->resume_done, msecs_to_jiffies(5000))) { rc = smscore_sendrequest_and_wait( - coredev, msg, msg->msgLength, + coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc < 0) - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " - "second try, rc %d", rc); + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d", + rc); } else rc = -ETIME; } @@ -767,31 +1290,39 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) return rc; } -static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { - /*Stellar NOVA A0 Nova B0 VEGA*/ - /*DVBT*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*DVBH*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*TDMB*/ - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, - /*DABIP*/ - {"none", "none", "none", "none"}, - /*BDA*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*ISDBTBDA*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*CMMB*/ - {"none", "none", "none", "cmmb_vega_12mhz.inp"} -}; - -static inline char *sms_get_fw_name(struct smscore_device_t *coredev, - int mode, enum sms_device_type_st type) +/** + * send init device request and wait for response + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * + * @return 0 on success, <0 on error. + */ +static int smscore_init_device(struct smscore_device_t *coredev, int mode) { - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; + void *buffer; + struct sms_msg_data *msg; + int rc = 0; + + buffer = kmalloc(sizeof(struct sms_msg_data) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (!buffer) { + sms_err("Could not allocate buffer for init device message."); + return -ENOMEM; + } + + msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct sms_msg_data)); + msg->msg_data[0] = mode; + + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->x_msg_header. msg_length, + &coredev->init_device_done); + + kfree(buffer); + return rc; } /** @@ -806,13 +1337,11 @@ static inline char *sms_get_fw_name(struct smscore_device_t *coredev, */ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) { - void *buffer; int rc = 0; - enum sms_device_type_st type; sms_debug("set device mode to %d", mode); if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { sms_err("invalid mode specified %d", mode); return -EINVAL; } @@ -833,58 +1362,21 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (!(coredev->modes_supported & (1 << mode))) { - char *fw_filename; - - type = smscore_registry_gettype(coredev->devpath); - fw_filename = sms_get_fw_name(coredev, mode, type); - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - if (rc < 0) { - sms_warn("error %d loading firmware: %s, " - "trying again with default firmware", - rc, fw_filename); - - /* try again with the default firmware */ - fw_filename = smscore_fw_lkup[mode][type]; - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - - if (rc < 0) { - sms_warn("error %d loading " - "firmware: %s", rc, - fw_filename); - return rc; - } - } - sms_log("firmware download success: %s", fw_filename); - } else - sms_info("mode %d supported by running " - "firmware", mode); - - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST *msg = - (struct SmsMsgData_ST *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); - msg->msgData[0] = mode; - - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, - &coredev->init_device_done); - - kfree(buffer); + mode, NULL); + if (rc >= 0) + sms_info("firmware download success"); } else { - sms_err("Could not allocate buffer for " - "init device message."); - rc = -ENOMEM; + sms_info("mode %d is already supported by running firmware", + mode); + } + if (coredev->fw_version >= 0x800) { + rc = smscore_init_device(coredev, mode); + if (rc < 0) + sms_err("device init failed, rc %d.", rc); } } else { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { sms_err("invalid mode specified %d", mode); return -EINVAL; } @@ -900,12 +1392,32 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (rc >= 0) { + char *buffer; coredev->mode = mode; coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + + buffer = kmalloc(sizeof(struct sms_msg_data) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct sms_msg_data *msg = (struct sms_msg_data *) SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct sms_msg_data)); + msg->msg_data[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->x_msg_header.msg_length, + &coredev->init_device_done); + + kfree(buffer); + } } if (rc < 0) sms_err("return error code %d.", rc); + else + sms_debug("Success setting device mode."); + return rc; } @@ -971,7 +1483,7 @@ found: */ void smscore_onresponse(struct smscore_device_t *coredev, struct smscore_buffer_t *cb) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) ((u8 *) cb->p + cb->offset); struct smscore_client_t *client; int rc = -EBUSY; @@ -983,7 +1495,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, last_sample_time = time_now; if (time_now - last_sample_time > 10000) { - sms_debug("\ndata rate %d bytes/secs", + sms_debug("data rate %d bytes/secs", (int)((data_total * 1000) / (time_now - last_sample_time))); @@ -993,14 +1505,14 @@ void smscore_onresponse(struct smscore_device_t *coredev, data_total += cb->size; /* Do we need to re-route? */ - if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || - (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if ((phdr->msg_type == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msg_type == MSG_SMS_TRANSMISSION_IND)) { if (coredev->mode == DEVICE_MODE_DVBT_BDA) - phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + phdr->msg_dst_id = DVBT_BDA_CONTROL_MSG_ID; } - client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + client = smscore_find_client(coredev, phdr->msg_type, phdr->msg_dst_id); /* If no client registered for type & id, * check for control client where type is not registered */ @@ -1008,57 +1520,75 @@ void smscore_onresponse(struct smscore_device_t *coredev, rc = client->onresponse_handler(client->context, cb); if (rc < 0) { - switch (phdr->msgType) { + switch (phdr->msg_type) { + case MSG_SMS_ISDBT_TUNE_RES: + break; + case MSG_SMS_RF_TUNE_RES: + break; + case MSG_SMS_SIGNAL_DETECTED_IND: + break; + case MSG_SMS_NO_SIGNAL_IND: + break; + case MSG_SMS_SPI_INT_LINE_SET_RES: + break; + case MSG_SMS_INTERFACE_LOCK_IND: + break; + case MSG_SMS_INTERFACE_UNLOCK_IND: + break; case MSG_SMS_GET_VERSION_EX_RES: { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) phdr; - sms_debug("MSG_SMS_GET_VERSION_EX_RES " - "id %d prots 0x%x ver %d.%d", - ver->FirmwareId, ver->SupportedProtocols, - ver->RomVersionMajor, ver->RomVersionMinor); - - coredev->mode = ver->FirmwareId == 255 ? - DEVICE_MODE_NONE : ver->FirmwareId; - coredev->modes_supported = ver->SupportedProtocols; + struct sms_version_res *ver = + (struct sms_version_res *) phdr; + sms_debug("Firmware id %d prots 0x%x ver %d.%d", + ver->firmware_id, ver->supported_protocols, + ver->rom_ver_major, ver->rom_ver_minor); + + coredev->mode = ver->firmware_id == 255 ? + DEVICE_MODE_NONE : ver->firmware_id; + coredev->modes_supported = ver->supported_protocols; + coredev->fw_version = ver->rom_ver_major << 8 | + ver->rom_ver_minor; complete(&coredev->version_ex_done); break; } case MSG_SMS_INIT_DEVICE_RES: - sms_debug("MSG_SMS_INIT_DEVICE_RES"); complete(&coredev->init_device_done); break; case MSG_SW_RELOAD_START_RES: - sms_debug("MSG_SW_RELOAD_START_RES"); complete(&coredev->reload_start_done); break; + case MSG_SMS_DATA_VALIDITY_RES: + { + struct sms_msg_data *validity = (struct sms_msg_data *) phdr; + + sms_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", + validity->msg_data[0]); + complete(&coredev->data_validity_done); + break; + } case MSG_SMS_DATA_DOWNLOAD_RES: complete(&coredev->data_download_done); break; case MSG_SW_RELOAD_EXEC_RES: - sms_debug("MSG_SW_RELOAD_EXEC_RES"); break; case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: - sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); complete(&coredev->trigger_done); break; case MSG_SMS_SLEEP_RESUME_COMP_IND: complete(&coredev->resume_done); break; case MSG_SMS_GPIO_CONFIG_EX_RES: - sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); complete(&coredev->gpio_configuration_done); break; case MSG_SMS_GPIO_SET_LEVEL_RES: - sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); complete(&coredev->gpio_set_level_done); break; case MSG_SMS_GPIO_GET_LEVEL_RES: { u32 *msgdata = (u32 *) phdr; coredev->gpio_get_res = msgdata[1]; - sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", + sms_debug("gpio level %d", coredev->gpio_get_res); complete(&coredev->gpio_get_level_done); break; @@ -1070,12 +1600,24 @@ void smscore_onresponse(struct smscore_device_t *coredev, sms_ir_event(coredev, (const char *) ((char *)phdr - + sizeof(struct SmsMsgHdr_ST)), - (int)phdr->msgLength - - sizeof(struct SmsMsgHdr_ST)); + + sizeof(struct sms_msg_hdr)), + (int)phdr->msg_length + - sizeof(struct sms_msg_hdr)); + break; + + case MSG_SMS_DVBT_BDA_DATA: + /* + * It can be received here, if the frontend is + * tuned into a valid channel and the proper firmware + * is loaded. That happens when the module got removed + * and re-inserted, without powering the device off + */ break; default: + sms_debug("message %s(%d) not handled.", + smscore_translate_msg(phdr->msg_type), + phdr->msg_type); break; } smscore_putbuffer(coredev, cb); @@ -1092,7 +1634,7 @@ EXPORT_SYMBOL_GPL(smscore_onresponse); * @return pointer to descriptor on success, NULL on error. */ -struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) +static struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) { struct smscore_buffer_t *cb = NULL; unsigned long flags; @@ -1257,7 +1799,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, void *buffer, size_t size) { struct smscore_device_t *coredev; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int rc; if (client == NULL) { @@ -1274,7 +1816,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, } rc = smscore_validate_client(client->coredev, client, 0, - phdr->msgSrcId); + phdr->msg_src_id); if (rc < 0) return rc; @@ -1288,16 +1830,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, struct smscore_config_gpio *pinconfig) { struct { - struct SmsMsgHdr_ST hdr; + struct sms_msg_hdr hdr; u32 data[6]; } msg; if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - msg.hdr.msgLength = sizeof(msg); + msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msg_dst_id = HIF_TASK; + msg.hdr.msg_flags = 0; + msg.hdr.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msg_length = sizeof(msg); msg.data[0] = pin; msg.data[1] = pinconfig->pullupdown; @@ -1306,16 +1848,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; switch (pinconfig->outputdriving) { - case SMS_GPIO_OUTPUTDRIVING_16mA: + case SMS_GPIO_OUTPUTDRIVING_S_16mA: msg.data[3] = 7; /* Nova - 16mA */ break; - case SMS_GPIO_OUTPUTDRIVING_12mA: + case SMS_GPIO_OUTPUTDRIVING_S_12mA: msg.data[3] = 5; /* Nova - 11mA */ break; - case SMS_GPIO_OUTPUTDRIVING_8mA: + case SMS_GPIO_OUTPUTDRIVING_S_8mA: msg.data[3] = 3; /* Nova - 7mA */ break; - case SMS_GPIO_OUTPUTDRIVING_4mA: + case SMS_GPIO_OUTPUTDRIVING_S_4mA: default: msg.data[3] = 2; /* Nova - 4mA */ break; @@ -1333,18 +1875,18 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) { struct { - struct SmsMsgHdr_ST hdr; + struct sms_msg_hdr hdr; u32 data[3]; } msg; if (pin > MAX_GPIO_PIN_NUMBER) return -EINVAL; - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - msg.hdr.msgLength = sizeof(msg); + msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msg_dst_id = HIF_TASK; + msg.hdr.msg_flags = 0; + msg.hdr.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msg_length = sizeof(msg); msg.data[0] = pin; msg.data[1] = level ? 1 : 0; @@ -1355,122 +1897,121 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) } /* new GPIO management implementation */ -static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, - u32 *pGroupNum, u32 *pGroupCfg) { - - *pGroupCfg = 1; - - if (PinNum <= 1) { - *pTranslatedPinNum = 0; - *pGroupNum = 9; - *pGroupCfg = 2; - } else if (PinNum >= 2 && PinNum <= 6) { - *pTranslatedPinNum = 2; - *pGroupNum = 0; - *pGroupCfg = 2; - } else if (PinNum >= 7 && PinNum <= 11) { - *pTranslatedPinNum = 7; - *pGroupNum = 1; - } else if (PinNum >= 12 && PinNum <= 15) { - *pTranslatedPinNum = 12; - *pGroupNum = 2; - *pGroupCfg = 3; - } else if (PinNum == 16) { - *pTranslatedPinNum = 16; - *pGroupNum = 23; - } else if (PinNum >= 17 && PinNum <= 24) { - *pTranslatedPinNum = 17; - *pGroupNum = 3; - } else if (PinNum == 25) { - *pTranslatedPinNum = 25; - *pGroupNum = 6; - } else if (PinNum >= 26 && PinNum <= 28) { - *pTranslatedPinNum = 26; - *pGroupNum = 4; - } else if (PinNum == 29) { - *pTranslatedPinNum = 29; - *pGroupNum = 5; - *pGroupCfg = 2; - } else if (PinNum == 30) { - *pTranslatedPinNum = 30; - *pGroupNum = 8; - } else if (PinNum == 31) { - *pTranslatedPinNum = 31; - *pGroupNum = 17; +static int get_gpio_pin_params(u32 pin_num, u32 *p_translatedpin_num, + u32 *p_group_num, u32 *p_group_cfg) { + + *p_group_cfg = 1; + + if (pin_num <= 1) { + *p_translatedpin_num = 0; + *p_group_num = 9; + *p_group_cfg = 2; + } else if (pin_num >= 2 && pin_num <= 6) { + *p_translatedpin_num = 2; + *p_group_num = 0; + *p_group_cfg = 2; + } else if (pin_num >= 7 && pin_num <= 11) { + *p_translatedpin_num = 7; + *p_group_num = 1; + } else if (pin_num >= 12 && pin_num <= 15) { + *p_translatedpin_num = 12; + *p_group_num = 2; + *p_group_cfg = 3; + } else if (pin_num == 16) { + *p_translatedpin_num = 16; + *p_group_num = 23; + } else if (pin_num >= 17 && pin_num <= 24) { + *p_translatedpin_num = 17; + *p_group_num = 3; + } else if (pin_num == 25) { + *p_translatedpin_num = 25; + *p_group_num = 6; + } else if (pin_num >= 26 && pin_num <= 28) { + *p_translatedpin_num = 26; + *p_group_num = 4; + } else if (pin_num == 29) { + *p_translatedpin_num = 29; + *p_group_num = 5; + *p_group_cfg = 2; + } else if (pin_num == 30) { + *p_translatedpin_num = 30; + *p_group_num = 8; + } else if (pin_num == 31) { + *p_translatedpin_num = 31; + *p_group_num = 17; } else return -1; - *pGroupCfg <<= 24; + *p_group_cfg <<= 24; return 0; } -int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig) { +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, + struct smscore_config_gpio *p_gpio_config) { - u32 totalLen; - u32 TranslatedPinNum = 0; - u32 GroupNum = 0; - u32 ElectricChar; - u32 groupCfg; + u32 total_len; + u32 translatedpin_num = 0; + u32 group_num = 0; + u32 electric_char; + u32 group_cfg; void *buffer; int rc; - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[6]; - } *pMsg; + struct set_gpio_msg { + struct sms_msg_hdr x_msg_header; + u32 msg_data[6]; + } *p_msg; - if (PinNum > MAX_GPIO_PIN_NUMBER) + if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - if (pGpioConfig == NULL) + if (p_gpio_config == NULL) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); + total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; - if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, - &groupCfg) != 0) { + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ; + if (get_gpio_pin_params(pin_num, &translatedpin_num, &group_num, + &group_cfg) != 0) { rc = -EINVAL; goto free; } - pMsg->msgData[1] = TranslatedPinNum; - pMsg->msgData[2] = GroupNum; - ElectricChar = (pGpioConfig->PullUpDown) - | (pGpioConfig->InputCharacteristics << 2) - | (pGpioConfig->OutputSlewRate << 3) - | (pGpioConfig->OutputDriving << 4); - pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = groupCfg; + p_msg->msg_data[1] = translatedpin_num; + p_msg->msg_data[2] = group_num; + electric_char = (p_gpio_config->pullupdown) + | (p_gpio_config->inputcharacteristics << 2) + | (p_gpio_config->outputslewrate << 3) + | (p_gpio_config->outputdriving << 4); + p_msg->msg_data[3] = electric_char; + p_msg->msg_data[4] = p_gpio_config->direction; + p_msg->msg_data[5] = group_cfg; } else { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = pGpioConfig->PullUpDown; - pMsg->msgData[2] = pGpioConfig->OutputSlewRate; - pMsg->msgData[3] = pGpioConfig->OutputDriving; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; + p_msg->msg_data[1] = p_gpio_config->pullupdown; + p_msg->msg_data[2] = p_gpio_config->outputslewrate; + p_msg->msg_data[3] = p_gpio_config->outputdriving; + p_msg->msg_data[4] = p_gpio_config->direction; + p_msg->msg_data[5] = 0; } - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_configuration_done); if (rc != 0) { @@ -1485,42 +2026,41 @@ free: return rc; } -int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel) { +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, + u8 new_level) { - u32 totalLen; + u32 total_len; int rc; void *buffer; - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[3]; /* keep it 3 ! */ - } *pMsg; + struct set_gpio_msg { + struct sms_msg_hdr x_msg_header; + u32 msg_data[3]; /* keep it 3 ! */ + } *p_msg; - if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) + if ((new_level > 1) || (pin_num > MAX_GPIO_PIN_NUMBER)) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + + total_len = sizeof(struct sms_msg_hdr) + (3 * sizeof(u32)); /* keep it 3 ! */ - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = NewLevel; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; + p_msg->msg_data[1] = new_level; /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_set_level_done); if (rc != 0) { @@ -1534,42 +2074,41 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, return rc; } -int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, u8 *level) { - u32 totalLen; + u32 total_len; int rc; void *buffer; - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; - } *pMsg; + struct set_gpio_msg { + struct sms_msg_hdr x_msg_header; + u32 msg_data[2]; + } *p_msg; - if (PinNum > MAX_GPIO_PIN_NUMBER) + if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); + total_len = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32)); - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = 0; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; + p_msg->msg_data[1] = 0; /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_get_level_done); if (rc != 0) { @@ -1635,3 +2174,27 @@ module_exit(smscore_module_exit); MODULE_DESCRIPTION("Siano MDTV Core module"); MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); + +/* This should match what's defined at smscoreapi.h */ +MODULE_FIRMWARE(SMS_FW_ATSC_DENVER); +MODULE_FIRMWARE(SMS_FW_CMMB_MING_APP); +MODULE_FIRMWARE(SMS_FW_CMMB_VEGA_12MHZ); +MODULE_FIRMWARE(SMS_FW_CMMB_VENICE_12MHZ); +MODULE_FIRMWARE(SMS_FW_DVBH_RIO); +MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ); +MODULE_FIRMWARE(SMS_FW_DVB_RIO); +MODULE_FIRMWARE(SMS_FW_FM_RADIO); +MODULE_FIRMWARE(SMS_FW_FM_RADIO_RIO); +MODULE_FIRMWARE(SMS_FW_DVBT_HCW_55XXX); +MODULE_FIRMWARE(SMS_FW_ISDBT_HCW_55XXX); +MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ); +MODULE_FIRMWARE(SMS_FW_ISDBT_PELE); +MODULE_FIRMWARE(SMS_FW_ISDBT_RIO); +MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_A); +MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_B); +MODULE_FIRMWARE(SMS_FW_DVBT_STELLAR); +MODULE_FIRMWARE(SMS_FW_TDMB_DENVER); +MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index c592ae09039..9c9063cd320 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -40,9 +40,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define kmutex_trylock(_p_) mutex_trylock(_p_) #define kmutex_unlock(_p_) mutex_unlock(_p_) -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif +/* + * Define the firmware names used by the driver. + * Those should match what's used at smscoreapi.c and sms-cards.c + * including the MODULE_FIRMWARE() macros at the end of smscoreapi.c + */ +#define SMS_FW_ATSC_DENVER "atsc_denver.inp" +#define SMS_FW_CMMB_MING_APP "cmmb_ming_app.inp" +#define SMS_FW_CMMB_VEGA_12MHZ "cmmb_vega_12mhz.inp" +#define SMS_FW_CMMB_VENICE_12MHZ "cmmb_venice_12mhz.inp" +#define SMS_FW_DVBH_RIO "dvbh_rio.inp" +#define SMS_FW_DVB_NOVA_12MHZ_B0 "dvb_nova_12mhz_b0.inp" +#define SMS_FW_DVB_NOVA_12MHZ "dvb_nova_12mhz.inp" +#define SMS_FW_DVB_RIO "dvb_rio.inp" +#define SMS_FW_FM_RADIO "fm_radio.inp" +#define SMS_FW_FM_RADIO_RIO "fm_radio_rio.inp" +#define SMS_FW_DVBT_HCW_55XXX "sms1xxx-hcw-55xxx-dvbt-02.fw" +#define SMS_FW_ISDBT_HCW_55XXX "sms1xxx-hcw-55xxx-isdbt-02.fw" +#define SMS_FW_ISDBT_NOVA_12MHZ_B0 "isdbt_nova_12mhz_b0.inp" +#define SMS_FW_ISDBT_NOVA_12MHZ "isdbt_nova_12mhz.inp" +#define SMS_FW_ISDBT_PELE "isdbt_pele.inp" +#define SMS_FW_ISDBT_RIO "isdbt_rio.inp" +#define SMS_FW_DVBT_NOVA_A "sms1xxx-nova-a-dvbt-01.fw" +#define SMS_FW_DVBT_NOVA_B "sms1xxx-nova-b-dvbt-01.fw" +#define SMS_FW_DVBT_STELLAR "sms1xxx-stellar-dvbt-01.fw" +#define SMS_FW_TDMB_DENVER "tdmb_denver.inp" +#define SMS_FW_TDMB_NOVA_12MHZ_B0 "tdmb_nova_12mhz_b0.inp" +#define SMS_FW_TDMB_NOVA_12MHZ "tdmb_nova_12mhz.inp" #define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) #define SMS_ALLOC_ALIGNMENT 128 @@ -50,18 +74,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define SMS_ALIGN_ADDRESS(addr) \ ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) +#define SMS_DEVICE_FAMILY1 0 #define SMS_DEVICE_FAMILY2 1 #define SMS_ROM_NO_RESPONSE 2 #define SMS_DEVICE_NOT_READY 0x8000000 enum sms_device_type_st { + SMS_UNKNOWN_TYPE = -1, SMS_STELLAR = 0, SMS_NOVA_A0, SMS_NOVA_B0, SMS_VEGA, + SMS_VENICE, + SMS_MING, + SMS_PELE, + SMS_RIO, + SMS_DENVER_1530, + SMS_DENVER_2160, SMS_NUM_OF_DEVICE_TYPES }; +enum sms_power_mode_st { + SMS_POWER_MODE_ACTIVE, + SMS_POWER_MODE_SUSPENDED +}; + struct smscore_device_t; struct smscore_client_t; struct smscore_buffer_t; @@ -149,6 +186,7 @@ struct smscore_device_t { /* host <--> device messages */ struct completion version_ex_done, data_download_done, trigger_done; + struct completion data_validity_done, device_ready_done; struct completion init_device_done, reload_start_done, resume_done; struct completion gpio_configuration_done, gpio_set_level_done; struct completion gpio_get_level_done, ir_init_done; @@ -165,10 +203,17 @@ struct smscore_device_t { /* Firmware */ u8 *fw_buf; u32 fw_buf_size; + u16 fw_version; /* Infrared (IR) */ struct ir_t ir; + /* + * Identify if device is USB or not. + * Used by smsdvb-sysfs to know the root node for debugfs + */ + bool is_usb_device; + int led_state; }; @@ -176,81 +221,363 @@ struct smscore_device_t { #define SMS_ANTENNA_GPIO_0 1 #define SMS_ANTENNA_GPIO_1 0 -#define BW_8_MHZ 0 -#define BW_7_MHZ 1 -#define BW_6_MHZ 2 -#define BW_5_MHZ 3 -#define BW_ISDBT_1SEG 4 -#define BW_ISDBT_3SEG 5 +enum sms_bandwidth_mode { + BW_8_MHZ = 0, + BW_7_MHZ = 1, + BW_6_MHZ = 2, + BW_5_MHZ = 3, + BW_ISDBT_1SEG = 4, + BW_ISDBT_3SEG = 5, + BW_2_MHZ = 6, + BW_FM_RADIO = 7, + BW_ISDBT_13SEG = 8, + BW_1_5_MHZ = 15, + BW_UNKNOWN = 0xffff +}; + #define MSG_HDR_FLAG_SPLIT_MSG 4 #define MAX_GPIO_PIN_NUMBER 31 #define HIF_TASK 11 +#define HIF_TASK_SLAVE 22 +#define HIF_TASK_SLAVE2 33 +#define HIF_TASK_SLAVE3 44 #define SMS_HOST_LIB 150 #define DVBT_BDA_CONTROL_MSG_ID 201 #define SMS_MAX_PAYLOAD_SIZE 240 #define SMS_TUNE_TIMEOUT 500 -#define MSG_SMS_GPIO_CONFIG_REQ 507 -#define MSG_SMS_GPIO_CONFIG_RES 508 -#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 -#define MSG_SMS_GPIO_SET_LEVEL_RES 510 -#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 -#define MSG_SMS_GPIO_GET_LEVEL_RES 512 -#define MSG_SMS_RF_TUNE_REQ 561 -#define MSG_SMS_RF_TUNE_RES 562 -#define MSG_SMS_INIT_DEVICE_REQ 578 -#define MSG_SMS_INIT_DEVICE_RES 579 -#define MSG_SMS_ADD_PID_FILTER_REQ 601 -#define MSG_SMS_ADD_PID_FILTER_RES 602 -#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 -#define MSG_SMS_REMOVE_PID_FILTER_RES 604 -#define MSG_SMS_DAB_CHANNEL 607 -#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 -#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 -#define MSG_SMS_GET_STATISTICS_RES 616 -#define MSG_SMS_GET_STATISTICS_REQ 615 -#define MSG_SMS_HO_PER_SLICES_IND 630 -#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 -#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 -#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 -#define MSG_SMS_DATA_DOWNLOAD_REQ 660 -#define MSG_SMS_DATA_DOWNLOAD_RES 661 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 -#define MSG_SMS_GET_VERSION_EX_REQ 668 -#define MSG_SMS_GET_VERSION_EX_RES 669 -#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 -#define MSG_SMS_I2C_SET_FREQ_REQ 685 -#define MSG_SMS_GENERIC_I2C_REQ 687 -#define MSG_SMS_GENERIC_I2C_RES 688 -#define MSG_SMS_DVBT_BDA_DATA 693 -#define MSG_SW_RELOAD_REQ 697 -#define MSG_SMS_DATA_MSG 699 -#define MSG_SW_RELOAD_START_REQ 702 -#define MSG_SW_RELOAD_START_RES 703 -#define MSG_SW_RELOAD_EXEC_REQ 704 -#define MSG_SW_RELOAD_EXEC_RES 705 -#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 -#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 -#define MSG_SMS_GPIO_CONFIG_EX_RES 713 -#define MSG_SMS_ISDBT_TUNE_REQ 776 -#define MSG_SMS_ISDBT_TUNE_RES 777 -#define MSG_SMS_TRANSMISSION_IND 782 -#define MSG_SMS_START_IR_REQ 800 -#define MSG_SMS_START_IR_RES 801 -#define MSG_SMS_IR_SAMPLES_IND 802 -#define MSG_SMS_SIGNAL_DETECTED_IND 827 -#define MSG_SMS_NO_SIGNAL_IND 828 +enum msg_types { + MSG_TYPE_BASE_VAL = 500, + MSG_SMS_GET_VERSION_REQ = 503, + MSG_SMS_GET_VERSION_RES = 504, + MSG_SMS_MULTI_BRIDGE_CFG = 505, + MSG_SMS_GPIO_CONFIG_REQ = 507, + MSG_SMS_GPIO_CONFIG_RES = 508, + MSG_SMS_GPIO_SET_LEVEL_REQ = 509, + MSG_SMS_GPIO_SET_LEVEL_RES = 510, + MSG_SMS_GPIO_GET_LEVEL_REQ = 511, + MSG_SMS_GPIO_GET_LEVEL_RES = 512, + MSG_SMS_EEPROM_BURN_IND = 513, + MSG_SMS_LOG_ENABLE_CHANGE_REQ = 514, + MSG_SMS_LOG_ENABLE_CHANGE_RES = 515, + MSG_SMS_SET_MAX_TX_MSG_LEN_REQ = 516, + MSG_SMS_SET_MAX_TX_MSG_LEN_RES = 517, + MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE = 518, + MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST = 519, + MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ = 520, + MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES = 521, + MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND = 522, + MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND = 523, + MSG_SMS_CONFIGURE_RF_SWITCH_REQ = 524, + MSG_SMS_CONFIGURE_RF_SWITCH_RES = 525, + MSG_SMS_MRC_PATH_DISCONNECT_REQ = 526, + MSG_SMS_MRC_PATH_DISCONNECT_RES = 527, + MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ = 528, + MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES = 529, + MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ = 530, + MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES = 531, + MSG_WR_REG_RFT_REQ = 533, + MSG_WR_REG_RFT_RES = 534, + MSG_RD_REG_RFT_REQ = 535, + MSG_RD_REG_RFT_RES = 536, + MSG_RD_REG_ALL_RFT_REQ = 537, + MSG_RD_REG_ALL_RFT_RES = 538, + MSG_HELP_INT = 539, + MSG_RUN_SCRIPT_INT = 540, + MSG_SMS_EWS_INBAND_REQ = 541, + MSG_SMS_EWS_INBAND_RES = 542, + MSG_SMS_RFS_SELECT_REQ = 543, + MSG_SMS_RFS_SELECT_RES = 544, + MSG_SMS_MB_GET_VER_REQ = 545, + MSG_SMS_MB_GET_VER_RES = 546, + MSG_SMS_MB_WRITE_CFGFILE_REQ = 547, + MSG_SMS_MB_WRITE_CFGFILE_RES = 548, + MSG_SMS_MB_READ_CFGFILE_REQ = 549, + MSG_SMS_MB_READ_CFGFILE_RES = 550, + MSG_SMS_RD_MEM_REQ = 552, + MSG_SMS_RD_MEM_RES = 553, + MSG_SMS_WR_MEM_REQ = 554, + MSG_SMS_WR_MEM_RES = 555, + MSG_SMS_UPDATE_MEM_REQ = 556, + MSG_SMS_UPDATE_MEM_RES = 557, + MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ = 558, + MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES = 559, + MSG_SMS_RF_TUNE_REQ = 561, + MSG_SMS_RF_TUNE_RES = 562, + MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ = 563, + MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES = 564, + MSG_SMS_ISDBT_SB_RECEPTION_REQ = 565, + MSG_SMS_ISDBT_SB_RECEPTION_RES = 566, + MSG_SMS_GENERIC_EPROM_WRITE_REQ = 567, + MSG_SMS_GENERIC_EPROM_WRITE_RES = 568, + MSG_SMS_GENERIC_EPROM_READ_REQ = 569, + MSG_SMS_GENERIC_EPROM_READ_RES = 570, + MSG_SMS_EEPROM_WRITE_REQ = 571, + MSG_SMS_EEPROM_WRITE_RES = 572, + MSG_SMS_CUSTOM_READ_REQ = 574, + MSG_SMS_CUSTOM_READ_RES = 575, + MSG_SMS_CUSTOM_WRITE_REQ = 576, + MSG_SMS_CUSTOM_WRITE_RES = 577, + MSG_SMS_INIT_DEVICE_REQ = 578, + MSG_SMS_INIT_DEVICE_RES = 579, + MSG_SMS_ATSC_SET_ALL_IP_REQ = 580, + MSG_SMS_ATSC_SET_ALL_IP_RES = 581, + MSG_SMS_ATSC_START_ENSEMBLE_REQ = 582, + MSG_SMS_ATSC_START_ENSEMBLE_RES = 583, + MSG_SMS_SET_OUTPUT_MODE_REQ = 584, + MSG_SMS_SET_OUTPUT_MODE_RES = 585, + MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ = 586, + MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES = 587, + MSG_SMS_SUB_CHANNEL_START_REQ = 589, + MSG_SMS_SUB_CHANNEL_START_RES = 590, + MSG_SMS_SUB_CHANNEL_STOP_REQ = 591, + MSG_SMS_SUB_CHANNEL_STOP_RES = 592, + MSG_SMS_ATSC_IP_FILTER_ADD_REQ = 593, + MSG_SMS_ATSC_IP_FILTER_ADD_RES = 594, + MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ = 595, + MSG_SMS_ATSC_IP_FILTER_REMOVE_RES = 596, + MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ = 597, + MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES = 598, + MSG_SMS_WAIT_CMD = 599, + MSG_SMS_ADD_PID_FILTER_REQ = 601, + MSG_SMS_ADD_PID_FILTER_RES = 602, + MSG_SMS_REMOVE_PID_FILTER_REQ = 603, + MSG_SMS_REMOVE_PID_FILTER_RES = 604, + MSG_SMS_FAST_INFORMATION_CHANNEL_REQ = 605, + MSG_SMS_FAST_INFORMATION_CHANNEL_RES = 606, + MSG_SMS_DAB_CHANNEL = 607, + MSG_SMS_GET_PID_FILTER_LIST_REQ = 608, + MSG_SMS_GET_PID_FILTER_LIST_RES = 609, + MSG_SMS_POWER_DOWN_REQ = 610, + MSG_SMS_POWER_DOWN_RES = 611, + MSG_SMS_ATSC_SLT_EXIST_IND = 612, + MSG_SMS_ATSC_NO_SLT_IND = 613, + MSG_SMS_GET_STATISTICS_REQ = 615, + MSG_SMS_GET_STATISTICS_RES = 616, + MSG_SMS_SEND_DUMP = 617, + MSG_SMS_SCAN_START_REQ = 618, + MSG_SMS_SCAN_START_RES = 619, + MSG_SMS_SCAN_STOP_REQ = 620, + MSG_SMS_SCAN_STOP_RES = 621, + MSG_SMS_SCAN_PROGRESS_IND = 622, + MSG_SMS_SCAN_COMPLETE_IND = 623, + MSG_SMS_LOG_ITEM = 624, + MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ = 628, + MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES = 629, + MSG_SMS_HO_PER_SLICES_IND = 630, + MSG_SMS_HO_INBAND_POWER_IND = 631, + MSG_SMS_MANUAL_DEMOD_REQ = 632, + MSG_SMS_HO_TUNE_ON_REQ = 636, + MSG_SMS_HO_TUNE_ON_RES = 637, + MSG_SMS_HO_TUNE_OFF_REQ = 638, + MSG_SMS_HO_TUNE_OFF_RES = 639, + MSG_SMS_HO_PEEK_FREQ_REQ = 640, + MSG_SMS_HO_PEEK_FREQ_RES = 641, + MSG_SMS_HO_PEEK_FREQ_IND = 642, + MSG_SMS_MB_ATTEN_SET_REQ = 643, + MSG_SMS_MB_ATTEN_SET_RES = 644, + MSG_SMS_ENABLE_STAT_IN_I2C_REQ = 649, + MSG_SMS_ENABLE_STAT_IN_I2C_RES = 650, + MSG_SMS_SET_ANTENNA_CONFIG_REQ = 651, + MSG_SMS_SET_ANTENNA_CONFIG_RES = 652, + MSG_SMS_GET_STATISTICS_EX_REQ = 653, + MSG_SMS_GET_STATISTICS_EX_RES = 654, + MSG_SMS_SLEEP_RESUME_COMP_IND = 655, + MSG_SMS_SWITCH_HOST_INTERFACE_REQ = 656, + MSG_SMS_SWITCH_HOST_INTERFACE_RES = 657, + MSG_SMS_DATA_DOWNLOAD_REQ = 660, + MSG_SMS_DATA_DOWNLOAD_RES = 661, + MSG_SMS_DATA_VALIDITY_REQ = 662, + MSG_SMS_DATA_VALIDITY_RES = 663, + MSG_SMS_SWDOWNLOAD_TRIGGER_REQ = 664, + MSG_SMS_SWDOWNLOAD_TRIGGER_RES = 665, + MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ = 666, + MSG_SMS_SWDOWNLOAD_BACKDOOR_RES = 667, + MSG_SMS_GET_VERSION_EX_REQ = 668, + MSG_SMS_GET_VERSION_EX_RES = 669, + MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ = 670, + MSG_SMS_CLOCK_OUTPUT_CONFIG_RES = 671, + MSG_SMS_I2C_SET_FREQ_REQ = 685, + MSG_SMS_I2C_SET_FREQ_RES = 686, + MSG_SMS_GENERIC_I2C_REQ = 687, + MSG_SMS_GENERIC_I2C_RES = 688, + MSG_SMS_DVBT_BDA_DATA = 693, + MSG_SW_RELOAD_REQ = 697, + MSG_SMS_DATA_MSG = 699, + MSG_TABLE_UPLOAD_REQ = 700, + MSG_TABLE_UPLOAD_RES = 701, + MSG_SW_RELOAD_START_REQ = 702, + MSG_SW_RELOAD_START_RES = 703, + MSG_SW_RELOAD_EXEC_REQ = 704, + MSG_SW_RELOAD_EXEC_RES = 705, + MSG_SMS_SPI_INT_LINE_SET_REQ = 710, + MSG_SMS_SPI_INT_LINE_SET_RES = 711, + MSG_SMS_GPIO_CONFIG_EX_REQ = 712, + MSG_SMS_GPIO_CONFIG_EX_RES = 713, + MSG_SMS_WATCHDOG_ACT_REQ = 716, + MSG_SMS_WATCHDOG_ACT_RES = 717, + MSG_SMS_LOOPBACK_REQ = 718, + MSG_SMS_LOOPBACK_RES = 719, + MSG_SMS_RAW_CAPTURE_START_REQ = 720, + MSG_SMS_RAW_CAPTURE_START_RES = 721, + MSG_SMS_RAW_CAPTURE_ABORT_REQ = 722, + MSG_SMS_RAW_CAPTURE_ABORT_RES = 723, + MSG_SMS_RAW_CAPTURE_COMPLETE_IND = 728, + MSG_SMS_DATA_PUMP_IND = 729, + MSG_SMS_DATA_PUMP_REQ = 730, + MSG_SMS_DATA_PUMP_RES = 731, + MSG_SMS_FLASH_DL_REQ = 732, + MSG_SMS_EXEC_TEST_1_REQ = 734, + MSG_SMS_EXEC_TEST_1_RES = 735, + MSG_SMS_ENBALE_TS_INTERFACE_REQ = 736, + MSG_SMS_ENBALE_TS_INTERFACE_RES = 737, + MSG_SMS_SPI_SET_BUS_WIDTH_REQ = 738, + MSG_SMS_SPI_SET_BUS_WIDTH_RES = 739, + MSG_SMS_SEND_EMM_REQ = 740, + MSG_SMS_SEND_EMM_RES = 741, + MSG_SMS_DISABLE_TS_INTERFACE_REQ = 742, + MSG_SMS_DISABLE_TS_INTERFACE_RES = 743, + MSG_SMS_IS_BUF_FREE_REQ = 744, + MSG_SMS_IS_BUF_FREE_RES = 745, + MSG_SMS_EXT_ANTENNA_REQ = 746, + MSG_SMS_EXT_ANTENNA_RES = 747, + MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE = 748, + MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE = 749, + MSG_SMS_BATTERY_LEVEL_REQ = 750, + MSG_SMS_BATTERY_LEVEL_RES = 751, + MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE = 752, + MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE = 753, + MSG_SMS_FM_RADIO_BLOCK_IND = 754, + MSG_SMS_HOST_NOTIFICATION_IND = 755, + MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE = 756, + MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE = 757, + MSG_SMS_CMMB_GET_NETWORKS_REQ = 760, + MSG_SMS_CMMB_GET_NETWORKS_RES = 761, + MSG_SMS_CMMB_START_SERVICE_REQ = 762, + MSG_SMS_CMMB_START_SERVICE_RES = 763, + MSG_SMS_CMMB_STOP_SERVICE_REQ = 764, + MSG_SMS_CMMB_STOP_SERVICE_RES = 765, + MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ = 768, + MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES = 769, + MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ = 770, + MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES = 771, + MSG_SMS_CMMB_START_CONTROL_INFO_REQ = 772, + MSG_SMS_CMMB_START_CONTROL_INFO_RES = 773, + MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ = 774, + MSG_SMS_CMMB_STOP_CONTROL_INFO_RES = 775, + MSG_SMS_ISDBT_TUNE_REQ = 776, + MSG_SMS_ISDBT_TUNE_RES = 777, + MSG_SMS_TRANSMISSION_IND = 782, + MSG_SMS_PID_STATISTICS_IND = 783, + MSG_SMS_POWER_DOWN_IND = 784, + MSG_SMS_POWER_DOWN_CONF = 785, + MSG_SMS_POWER_UP_IND = 786, + MSG_SMS_POWER_UP_CONF = 787, + MSG_SMS_POWER_MODE_SET_REQ = 790, + MSG_SMS_POWER_MODE_SET_RES = 791, + MSG_SMS_DEBUG_HOST_EVENT_REQ = 792, + MSG_SMS_DEBUG_HOST_EVENT_RES = 793, + MSG_SMS_NEW_CRYSTAL_REQ = 794, + MSG_SMS_NEW_CRYSTAL_RES = 795, + MSG_SMS_CONFIG_SPI_REQ = 796, + MSG_SMS_CONFIG_SPI_RES = 797, + MSG_SMS_I2C_SHORT_STAT_IND = 798, + MSG_SMS_START_IR_REQ = 800, + MSG_SMS_START_IR_RES = 801, + MSG_SMS_IR_SAMPLES_IND = 802, + MSG_SMS_CMMB_CA_SERVICE_IND = 803, + MSG_SMS_SLAVE_DEVICE_DETECTED = 804, + MSG_SMS_INTERFACE_LOCK_IND = 805, + MSG_SMS_INTERFACE_UNLOCK_IND = 806, + MSG_SMS_SEND_ROSUM_BUFF_REQ = 810, + MSG_SMS_SEND_ROSUM_BUFF_RES = 811, + MSG_SMS_ROSUM_BUFF = 812, + MSG_SMS_SET_AES128_KEY_REQ = 815, + MSG_SMS_SET_AES128_KEY_RES = 816, + MSG_SMS_MBBMS_WRITE_REQ = 817, + MSG_SMS_MBBMS_WRITE_RES = 818, + MSG_SMS_MBBMS_READ_IND = 819, + MSG_SMS_IQ_STREAM_START_REQ = 820, + MSG_SMS_IQ_STREAM_START_RES = 821, + MSG_SMS_IQ_STREAM_STOP_REQ = 822, + MSG_SMS_IQ_STREAM_STOP_RES = 823, + MSG_SMS_IQ_STREAM_DATA_BLOCK = 824, + MSG_SMS_GET_EEPROM_VERSION_REQ = 825, + MSG_SMS_GET_EEPROM_VERSION_RES = 826, + MSG_SMS_SIGNAL_DETECTED_IND = 827, + MSG_SMS_NO_SIGNAL_IND = 828, + MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ = 830, + MSG_SMS_MRC_SHUTDOWN_SLAVE_RES = 831, + MSG_SMS_MRC_BRINGUP_SLAVE_REQ = 832, + MSG_SMS_MRC_BRINGUP_SLAVE_RES = 833, + MSG_SMS_EXTERNAL_LNA_CTRL_REQ = 834, + MSG_SMS_EXTERNAL_LNA_CTRL_RES = 835, + MSG_SMS_SET_PERIODIC_STATISTICS_REQ = 836, + MSG_SMS_SET_PERIODIC_STATISTICS_RES = 837, + MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ = 838, + MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES = 839, + LOCAL_TUNE = 850, + LOCAL_IFFT_H_ICI = 851, + MSG_RESYNC_REQ = 852, + MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ = 853, + MSG_SMS_CMMB_GET_MRC_STATISTICS_RES = 854, + MSG_SMS_LOG_EX_ITEM = 855, + MSG_SMS_DEVICE_DATA_LOSS_IND = 856, + MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND = 857, + MSG_SMS_USER_MSG_REQ = 858, + MSG_SMS_USER_MSG_RES = 859, + MSG_SMS_SMART_CARD_INIT_REQ = 860, + MSG_SMS_SMART_CARD_INIT_RES = 861, + MSG_SMS_SMART_CARD_WRITE_REQ = 862, + MSG_SMS_SMART_CARD_WRITE_RES = 863, + MSG_SMS_SMART_CARD_READ_IND = 864, + MSG_SMS_TSE_ENABLE_REQ = 866, + MSG_SMS_TSE_ENABLE_RES = 867, + MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ = 868, + MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES = 869, + MSG_SMS_LED_CONFIG_REQ = 870, + MSG_SMS_LED_CONFIG_RES = 871, + MSG_PWM_ANTENNA_REQ = 872, + MSG_PWM_ANTENNA_RES = 873, + MSG_SMS_CMMB_SMD_SN_REQ = 874, + MSG_SMS_CMMB_SMD_SN_RES = 875, + MSG_SMS_CMMB_SET_CA_CW_REQ = 876, + MSG_SMS_CMMB_SET_CA_CW_RES = 877, + MSG_SMS_CMMB_SET_CA_SALT_REQ = 878, + MSG_SMS_CMMB_SET_CA_SALT_RES = 879, + MSG_SMS_NSCD_INIT_REQ = 880, + MSG_SMS_NSCD_INIT_RES = 881, + MSG_SMS_NSCD_PROCESS_SECTION_REQ = 882, + MSG_SMS_NSCD_PROCESS_SECTION_RES = 883, + MSG_SMS_DBD_CREATE_OBJECT_REQ = 884, + MSG_SMS_DBD_CREATE_OBJECT_RES = 885, + MSG_SMS_DBD_CONFIGURE_REQ = 886, + MSG_SMS_DBD_CONFIGURE_RES = 887, + MSG_SMS_DBD_SET_KEYS_REQ = 888, + MSG_SMS_DBD_SET_KEYS_RES = 889, + MSG_SMS_DBD_PROCESS_HEADER_REQ = 890, + MSG_SMS_DBD_PROCESS_HEADER_RES = 891, + MSG_SMS_DBD_PROCESS_DATA_REQ = 892, + MSG_SMS_DBD_PROCESS_DATA_RES = 893, + MSG_SMS_DBD_PROCESS_GET_DATA_REQ = 894, + MSG_SMS_DBD_PROCESS_GET_DATA_RES = 895, + MSG_SMS_NSCD_OPEN_SESSION_REQ = 896, + MSG_SMS_NSCD_OPEN_SESSION_RES = 897, + MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ = 898, + MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES = 899, + MSG_LAST_MSG_TYPE = 900, +}; #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ - (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ - (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ + (ptr)->msg_type = type; \ + (ptr)->msg_src_id = src; \ + (ptr)->msg_dst_id = dst; \ + (ptr)->msg_length = len; \ + (ptr)->msg_flags = 0; \ } while (0) #define SMS_INIT_MSG(ptr, type, len) \ @@ -277,228 +604,296 @@ enum SMS_DEVICE_MODE { DEVICE_MODE_ISDBT_BDA, DEVICE_MODE_CMMB, DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_FM_RADIO, + DEVICE_MODE_FM_RADIO_BDA, + DEVICE_MODE_ATSC, DEVICE_MODE_MAX, }; -struct SmsMsgHdr_ST { - u16 msgType; - u8 msgSrcId; - u8 msgDstId; - u16 msgLength; /* Length of entire message, including header */ - u16 msgFlags; +struct sms_msg_hdr { + u16 msg_type; + u8 msg_src_id; + u8 msg_dst_id; + u16 msg_length; /* length of entire message, including header */ + u16 msg_flags; +}; + +struct sms_msg_data { + struct sms_msg_hdr x_msg_header; + u32 msg_data[1]; }; -struct SmsMsgData_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[1]; +struct sms_msg_data2 { + struct sms_msg_hdr x_msg_header; + u32 msg_data[2]; }; -struct SmsMsgData_ST2 { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; +struct sms_msg_data4 { + struct sms_msg_hdr x_msg_header; + u32 msg_data[4]; }; -struct SmsDataDownload_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 MemAddr; - u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +struct sms_data_download { + struct sms_msg_hdr x_msg_header; + u32 mem_addr; + u8 payload[SMS_MAX_PAYLOAD_SIZE]; }; -struct SmsVersionRes_ST { - struct SmsMsgHdr_ST xMsgHeader; +struct sms_version_res { + struct sms_msg_hdr x_msg_header; - u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ - u8 Step; /* 0 - Step A */ - u8 MetalFix; /* 0 - Metal 0 */ + u16 chip_model; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 step; /* 0 - step A */ + u8 metal_fix; /* 0 - Metal 0 */ - /* FirmwareId 0xFF if ROM, otherwise the + /* firmware_id 0xFF if ROM, otherwise the * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ - u8 FirmwareId; - /* SupportedProtocols Bitwise OR combination of + u8 firmware_id; + /* supported_protocols Bitwise OR combination of * supported protocols */ - u8 SupportedProtocols; + u8 supported_protocols; - u8 VersionMajor; - u8 VersionMinor; - u8 VersionPatch; - u8 VersionFieldPatch; + u8 version_major; + u8 version_minor; + u8 version_patch; + u8 version_field_patch; - u8 RomVersionMajor; - u8 RomVersionMinor; - u8 RomVersionPatch; - u8 RomVersionFieldPatch; + u8 rom_ver_major; + u8 rom_ver_minor; + u8 rom_ver_patch; + u8 rom_ver_field_patch; u8 TextLabel[34]; }; -struct SmsFirmware_ST { - u32 CheckSum; - u32 Length; - u32 StartAddress; - u8 Payload[1]; +struct sms_firmware { + u32 check_sum; + u32 length; + u32 start_address; + u8 payload[1]; }; -/* Statistics information returned as response for - * SmsHostApiGetStatistics_Req */ -struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ +/* statistics information returned as response for + * SmsHostApiGetstatistics_Req */ +struct sms_stats { + u32 reserved; /* reserved */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ + u32 ber; /* Post Viterbi ber [1E-5] */ u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ - u32 TS_PER; /* Transport stream PER, + u32 ts_per; /* Transport stream PER, 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ - u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz, valid only for DVB-T/H */ + u32 transmission_mode; /* Transmission Mode, for DAB modes 1-4, for DVB-T/H FFT mode carriers in Kilos */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, valid only for DVB-T/H */ - u32 GuardInterval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + u32 guard_interval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 LPCodeRate; /* Low Priority Code Rate from + u32 lp_code_rate; /* Low Priority Code Rate from SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET, valid only for DVB-T/H */ - u32 Constellation; /* Constellation from + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes, + u32 burst_size; /* Current burst size in bytes, valid only for DVB-H */ - u32 BurstDuration; /* Current burst duration in mSec, + u32 burst_duration; /* Current burst duration in mSec, valid only for DVB-H */ - u32 BurstCycleTime; /* Current burst cycle time in mSec, + u32 burst_cycle_time; /* Current burst cycle time in mSec, valid only for DVB-H */ - u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + u32 calc_burst_cycle_time;/* Current burst cycle time in mSec, as calculated by demodulator, valid only for DVB-H */ - u32 NumOfRows; /* Number of rows in MPE table, + u32 num_of_rows; /* Number of rows in MPE table, valid only for DVB-H */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table, + u32 num_of_padd_cols; /* Number of padding columns in MPE table, valid only for DVB-H */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + u32 num_of_punct_cols; /* Number of puncturing columns in MPE table, valid only for DVB-H */ - u32 ErrorTSPackets; /* Number of erroneous + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + u32 total_ts_packets; /* Total number of transport-stream packets */ + u32 num_of_valid_mpe_tlbs; /* Number of MPE tables which do not include errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + u32 num_of_invalid_mpe_tlbs;/* Number of MPE tables which include errors after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were + u32 num_of_corrected_mpe_tlbs;/* Number of MPE tables which were corrected by MPE RS decoding */ /* Common params */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of errornous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi ber [1E-5] */ /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + u32 num_mpe_received; /* DVB-H, Num MPE section received */ - u32 ReservedFields[10]; /* Reserved */ + u32 reservedFields[10]; /* reserved */ }; -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; +struct sms_msg_statistics_info { + u32 request_result; - struct SMSHOSTLIB_STATISTICS_ST Stat; + struct sms_stats stat; /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ + u32 signal; /* dB */ + u32 noise; /* dB */ }; -struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { +struct sms_isdbt_layer_stats { /* Per-layer information */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, * 255 means layer does not exist */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET, * 255 means layer does not exist */ - u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 BERErrorCount; /* Post Viterbi Error Bits Count */ - u32 BERBitCount; /* Post Viterbi Total Bits Count */ - u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 TILdepthI; /* Time interleaver depth I parameter, + u32 ber; /* Post Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */ + u32 ber_error_count; /* Post Viterbi Error Bits Count */ + u32 ber_bit_count; /* Post Viterbi Total Bits Count */ + u32 pre_ber; /* Pre Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */ + u32 ts_per; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ + u32 ti_ldepth_i; /* Time interleaver depth I parameter, * 255 means layer does not exist */ - u32 NumberOfSegments; /* Number of segments in layer A, + u32 number_of_segments; /* Number of segments in layer A, * 255 means layer does not exist */ - u32 TMCCErrors; /* TMCC errors */ + u32 tmcc_errors; /* TMCC errors */ }; -struct SMSHOSTLIB_STATISTICS_ISDBT_ST { - u32 StatisticsType; /* Enumerator identifying the type of the +struct sms_isdbt_stats { + u32 statistics_type; /* Enumerator identifying the type of the * structure. Values are the same as * SMSHOSTLIB_DEVICE_MODES_E * * This field MUST always be first in any * statistics structure */ - u32 FullSize; /* Total size of the structure returned by the modem. + u32 full_size; /* Total size of the structure returned by the modem. * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ + * full_size, the struct will be truncated */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ s32 SNR; /* dB */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in Hz */ /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* ISDB-T transmission mode */ + u32 modem_state; /* 0 - Acquisition, 1 - Locked */ + u32 guard_interval; /* Guard Interval, 1 divided by value */ + u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */ + u32 num_of_layers; /* Number of ISDB-T layers in the network */ /* Per-layer information */ /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + struct sms_isdbt_layer_stats layer_info[3]; + /* Per-layer statistics, see sms_isdbt_layer_stats */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ }; -struct PID_STATISTICS_DATA_S { +struct sms_isdbt_stats_ex { + u32 statistics_type; /* Enumerator identifying the type of the + * structure. Values are the same as + * SMSHOSTLIB_DEVICE_MODES_E + * + * This field MUST always be first in any + * statistics structure */ + + u32 full_size; /* Total size of the structure returned by the modem. + * If the size requested by the host is smaller than + * full_size, the struct will be truncated */ + + /* Common parameters */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + s32 RSSI; /* dBm */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in Hz */ + + /* Transmission parameters */ + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* ISDB-T transmission mode */ + u32 modem_state; /* 0 - Acquisition, 1 - Locked */ + u32 guard_interval; /* Guard Interval, 1 divided by value */ + u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */ + u32 num_of_layers; /* Number of ISDB-T layers in the network */ + + u32 segment_number; /* Segment number for ISDB-Tsb */ + u32 tune_bw; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */ + + /* Per-layer information */ + /* Layers A, B and C */ + struct sms_isdbt_layer_stats layer_info[3]; + /* Per-layer statistics, see sms_isdbt_layer_stats */ + + /* Interface information */ + u32 reserved1; /* Was sms_to_host_tx_errors - obsolete . */ + /* Proprietary information */ + u32 ext_antenna; /* Obsolete field. */ + u32 reception_quality; + u32 ews_alert_active; /* signals if EWS alert is currently on */ + u32 lna_on_off; /* Internal LNA state: 0: OFF, 1: ON */ + + u32 rf_agc_level; /* RF AGC Level [linear units], full gain = 65535 (20dB) */ + u32 bb_agc_level; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */ + u32 fw_errors_counter; /* Application errors - should be always zero */ + u8 FwErrorsHistoryArr[8]; /* Last FW errors IDs - first is most recent, last is oldest */ + + s32 MRC_SNR; /* dB */ + u32 snr_full_res; /* dB x 65536 */ + u32 reserved4[4]; +}; + + +struct sms_pid_stats_data { struct PID_BURST_S { u32 size; u32 padding_cols; @@ -513,112 +908,155 @@ struct PID_STATISTICS_DATA_S { u32 tot_cor_tbl; }; -struct PID_DATA_S { +struct sms_pid_data { u32 pid; u32 num_rows; - struct PID_STATISTICS_DATA_S pid_statistics; + struct sms_pid_stats_data pid_statistics; }; #define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) -#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.bandwidth = 8 - _stat.bandwidth) #define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ - if (_stat.TransmissionMode == 0) \ - _stat.TransmissionMode = 2; \ - else if (_stat.TransmissionMode == 1) \ - _stat.TransmissionMode = 8; \ + if (_stat.transmission_mode == 0) \ + _stat.transmission_mode = 2; \ + else if (_stat.transmission_mode == 1) \ + _stat.transmission_mode = 8; \ else \ - _stat.TransmissionMode = 4; + _stat.transmission_mode = 4; -struct TRANSMISSION_STATISTICS_S { - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* FFT mode carriers in Kilos */ - u32 GuardInterval; /* Guard Interval from +struct sms_tx_stats { + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* FFT mode carriers in Kilos */ + u32 guard_interval; /* Guard Interval from SMSHOSTLIB_GUARD_INTERVALS_ET */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 lp_code_rate; /* Low Priority Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ - u32 Constellation; /* Constellation from + u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET */ /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ +}; + +struct sms_rx_stats { + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ + + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 ber; /* Post Viterbi ber [1E-5] */ + u32 ber_error_count; /* Number of erroneous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ + u32 ts_per; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ + u32 error_ts_packets; /* Number of erroneous + transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 mrc_in_band_pwr; /* In band power in dBM */ }; -struct RECEPTION_STATISTICS_S { - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ +struct sms_rx_stats_ex { + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, + u32 ber; /* Post Viterbi ber [1E-5] */ + u32 ber_error_count; /* Number of erroneous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ + u32 ts_per; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - u32 ErrorTSPackets; /* Number of erroneous + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ + + s32 ref_dev_ppm; + s32 freq_dev_hz; s32 MRC_SNR; /* dB */ s32 MRC_RSSI; /* dBm */ - s32 MRC_InBandPwr; /* In band power in dBM */ + s32 mrc_in_band_pwr; /* In band power in dBM */ }; -/* Statistics information returned as response for - * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ -struct SMSHOSTLIB_STATISTICS_DVB_S { +/* statistics information returned as response for + * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ +struct sms_stats_dvb { /* Reception */ - struct RECEPTION_STATISTICS_S ReceptionData; + struct sms_rx_stats reception_data; /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S TransmissionData; + struct sms_tx_stats transmission_data; /* Burst parameters, valid only for DVB-H */ #define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; + struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; }; -struct SRVM_SIGNAL_STATUS_S { +/* statistics information returned as response for + * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ +struct sms_stats_dvb_ex { + /* Reception */ + struct sms_rx_stats_ex reception_data; + + /* Transmission parameters */ + struct sms_tx_stats transmission_data; + + /* Burst parameters, valid only for DVB-H */ +#define SRVM_MAX_PID_FILTERS 8 + struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; +}; + +struct sms_srvm_signal_status { u32 result; u32 snr; - u32 tsPackets; - u32 etsPackets; + u32 ts_packets; + u32 ets_packets; u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; + u32 hp_code; + u32 tps_srv_ind_lp; + u32 tps_srv_ind_hp; + u32 cell_id; u32 reason; - s32 inBandPower; - u32 requestId; + s32 in_band_power; + u32 request_id; }; -struct SMSHOSTLIB_I2C_REQ_ST { - u32 DeviceAddress; /* I2c device address */ - u32 WriteCount; /* number of bytes to write */ - u32 ReadCount; /* number of bytes to read */ +struct sms_i2c_req { + u32 device_address; /* I2c device address */ + u32 write_count; /* number of bytes to write */ + u32 read_count; /* number of bytes to read */ u8 Data[1]; }; -struct SMSHOSTLIB_I2C_RES_ST { - u32 Status; /* non-zero value in case of failure */ - u32 ReadCount; /* number of bytes read */ +struct sms_i2c_res { + u32 status; /* non-zero value in case of failure */ + u32 read_count; /* number of bytes read */ u8 Data[1]; }; @@ -638,59 +1076,39 @@ struct smscore_config_gpio { #define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 u8 inputcharacteristics; -#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 -#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 - u8 outputslewrate; - -#define SMS_GPIO_OUTPUTDRIVING_4mA 0 -#define SMS_GPIO_OUTPUTDRIVING_8mA 1 -#define SMS_GPIO_OUTPUTDRIVING_12mA 2 -#define SMS_GPIO_OUTPUTDRIVING_16mA 3 - u8 outputdriving; -}; - -struct smscore_gpio_config { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 Direction; - -#define SMS_GPIO_PULL_UP_DOWN_NONE 0 -#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 -#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 -#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 - u8 PullUpDown; - -#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 - u8 InputCharacteristics; - -#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ + /* 10xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 +#define SMS_GPIO_OUTPUT_SLEW_WRATE_SLOW 1 + /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 +#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 +#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ - u8 OutputSlewRate; + u8 outputslewrate; -#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ + /* 10xx */ +#define SMS_GPIO_OUTPUTDRIVING_S_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_S_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_S_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_S_16mA 3 + + /* 11xx*/ +#define SMS_GPIO_OUTPUTDRIVING_1_5mA 0 +#define SMS_GPIO_OUTPUTDRIVING_2_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_4mA 2 +#define SMS_GPIO_OUTPUTDRIVING_7mA 3 +#define SMS_GPIO_OUTPUTDRIVING_10mA 4 +#define SMS_GPIO_OUTPUTDRIVING_11mA 5 +#define SMS_GPIO_OUTPUTDRIVING_14mA 6 +#define SMS_GPIO_OUTPUTDRIVING_16mA 7 -#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ - u8 OutputDriving; + u8 outputdriving; }; -extern void smscore_registry_setmode(char *devpath, int mode); +char *smscore_translate_msg(enum msg_types msgtype); + extern int smscore_registry_getmode(char *devpath); extern int smscore_register_hotplug(hotplug_t hotplug); @@ -721,8 +1139,6 @@ extern void smscore_onresponse(struct smscore_device_t *coredev, extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); extern int smscore_map_common_buffer(struct smscore_device_t *coredev, struct vm_area_struct *vma); -extern int smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, char *filename); extern int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf, int size); @@ -737,11 +1153,11 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); /* new GPIO management */ -extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig); -extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel); -extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, +extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, + struct smscore_config_gpio *p_gpio_config); +extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, + u8 new_level); +extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, u8 *level); void smscore_set_board_id(struct smscore_device_t *core, int id); @@ -760,7 +1176,8 @@ int smscore_led_state(struct smscore_device_t *core, int led); #define dprintk(kern, lvl, fmt, arg...) do {\ if (sms_dbg & lvl) \ - sms_printk(kern, fmt, ##arg); } while (0) + sms_printk(kern, fmt, ##arg); \ +} while (0) #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) #define sms_err(fmt, arg...) \ diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c new file mode 100644 index 00000000000..2408d7e9451 --- /dev/null +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -0,0 +1,551 @@ +/*********************************************************************** + * + * Copyright(c) 2013 Mauro Carvalho Chehab + * + * 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, see <http://www.gnu.org/licenses/>. + * + ***********************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/debugfs.h> +#include <linux/spinlock.h> +#include <linux/usb.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" + +#include "smsdvb.h" + +static struct dentry *smsdvb_debugfs_usb_root; + +struct smsdvb_debugfs { + struct kref refcount; + spinlock_t lock; + + char stats_data[PAGE_SIZE]; + unsigned stats_count; + bool stats_was_read; + + wait_queue_head_t stats_queue; +}; + +static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, + struct sms_stats *p) +{ + int n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_rf_locked = %d\n", p->is_rf_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_demod_locked = %d\n", p->is_demod_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_external_lna_on = %d\n", p->is_external_lna_on); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d\n", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ber = %d\n", p->ber); + n += snprintf(&buf[n], PAGE_SIZE - n, + "FIB_CRC = %d\n", p->FIB_CRC); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ts_per = %d\n", p->ts_per); + n += snprintf(&buf[n], PAGE_SIZE - n, + "MFER = %d\n", p->MFER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d\n", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "in_band_pwr = %d\n", p->in_band_pwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "carrier_offset = %d\n", p->carrier_offset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "modem_state = %d\n", p->modem_state); + n += snprintf(&buf[n], PAGE_SIZE - n, + "frequency = %d\n", p->frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "bandwidth = %d\n", p->bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "transmission_mode = %d\n", p->transmission_mode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "modem_state = %d\n", p->modem_state); + n += snprintf(&buf[n], PAGE_SIZE - n, + "guard_interval = %d\n", p->guard_interval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "code_rate = %d\n", p->code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "lp_code_rate = %d\n", p->lp_code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "hierarchy = %d\n", p->hierarchy); + n += snprintf(&buf[n], PAGE_SIZE - n, + "constellation = %d\n", p->constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, + "burst_size = %d\n", p->burst_size); + n += snprintf(&buf[n], PAGE_SIZE - n, + "burst_duration = %d\n", p->burst_duration); + n += snprintf(&buf[n], PAGE_SIZE - n, + "burst_cycle_time = %d\n", p->burst_cycle_time); + n += snprintf(&buf[n], PAGE_SIZE - n, + "calc_burst_cycle_time = %d\n", + p->calc_burst_cycle_time); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_rows = %d\n", p->num_of_rows); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_padd_cols = %d\n", p->num_of_padd_cols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_punct_cols = %d\n", p->num_of_punct_cols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "error_ts_packets = %d\n", p->error_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "total_ts_packets = %d\n", p->total_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ber_error_count = %d\n", p->ber_error_count); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ber_bit_count = %d\n", p->ber_bit_count); + n += snprintf(&buf[n], PAGE_SIZE - n, + "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); + n += snprintf(&buf[n], PAGE_SIZE - n, + "pre_ber = %d\n", p->pre_ber); + n += snprintf(&buf[n], PAGE_SIZE - n, + "cell_id = %d\n", p->cell_id); + n += snprintf(&buf[n], PAGE_SIZE - n, + "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp); + n += snprintf(&buf[n], PAGE_SIZE - n, + "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_mpe_received = %d\n", p->num_mpe_received); + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + wake_up(&debug_data->stats_queue); +} + +static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, + struct sms_isdbt_stats *p) +{ + int i, n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "statistics_type = %d\t", p->statistics_type); + n += snprintf(&buf[n], PAGE_SIZE - n, + "full_size = %d\n", p->full_size); + + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_rf_locked = %d\t\t", p->is_rf_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_demod_locked = %d\t", p->is_demod_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_external_lna_on = %d\n", p->is_external_lna_on); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "in_band_pwr = %d dBm\n", p->in_band_pwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "carrier_offset = %d\t", p->carrier_offset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "bandwidth = %d\t\t", p->bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "frequency = %d Hz\n", p->frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "transmission_mode = %d\t", p->transmission_mode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "modem_state = %d\t\t", p->modem_state); + n += snprintf(&buf[n], PAGE_SIZE - n, + "guard_interval = %d\n", p->guard_interval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "system_type = %d\t\t", p->system_type); + n += snprintf(&buf[n], PAGE_SIZE - n, + "partial_reception = %d\t", p->partial_reception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_layers = %d\n", p->num_of_layers); + n += snprintf(&buf[n], PAGE_SIZE - n, + "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); + + for (i = 0; i < 3; i++) { + if (p->layer_info[i].number_of_segments < 1 || + p->layer_info[i].number_of_segments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", + p->layer_info[i].code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", + p->layer_info[i].constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", + p->layer_info[i].ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", + p->layer_info[i].ber_error_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", + p->layer_info[i].ber_bit_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", + p->layer_info[i].pre_ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", + p->layer_info[i].ts_per); + n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", + p->layer_info[i].error_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", + p->layer_info[i].total_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", + p->layer_info[i].ti_ldepth_i); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tnumber_of_segments = %d\t", + p->layer_info[i].number_of_segments); + n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", + p->layer_info[i].tmcc_errors); + } + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + wake_up(&debug_data->stats_queue); +} + +static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, + struct sms_isdbt_stats_ex *p) +{ + int i, n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "statistics_type = %d\t", p->statistics_type); + n += snprintf(&buf[n], PAGE_SIZE - n, + "full_size = %d\n", p->full_size); + + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_rf_locked = %d\t\t", p->is_rf_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_demod_locked = %d\t", p->is_demod_locked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "is_external_lna_on = %d\n", p->is_external_lna_on); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "in_band_pwr = %d dBm\n", p->in_band_pwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "carrier_offset = %d\t", p->carrier_offset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "bandwidth = %d\t\t", p->bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "frequency = %d Hz\n", p->frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "transmission_mode = %d\t", p->transmission_mode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "modem_state = %d\t\t", p->modem_state); + n += snprintf(&buf[n], PAGE_SIZE - n, + "guard_interval = %d\n", p->guard_interval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "system_type = %d\t\t", p->system_type); + n += snprintf(&buf[n], PAGE_SIZE - n, + "partial_reception = %d\t", p->partial_reception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "num_of_layers = %d\n", p->num_of_layers); + n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", + p->segment_number); + n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", + p->tune_bw); + + for (i = 0; i < 3; i++) { + if (p->layer_info[i].number_of_segments < 1 || + p->layer_info[i].number_of_segments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", + p->layer_info[i].code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", + p->layer_info[i].constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", + p->layer_info[i].ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", + p->layer_info[i].ber_error_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", + p->layer_info[i].ber_bit_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", + p->layer_info[i].pre_ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", + p->layer_info[i].ts_per); + n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", + p->layer_info[i].error_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", + p->layer_info[i].total_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", + p->layer_info[i].ti_ldepth_i); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tnumber_of_segments = %d\t", + p->layer_info[i].number_of_segments); + n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", + p->layer_info[i].tmcc_errors); + } + + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + + wake_up(&debug_data->stats_queue); +} + +static int smsdvb_stats_open(struct inode *inode, struct file *file) +{ + struct smsdvb_client_t *client = inode->i_private; + struct smsdvb_debugfs *debug_data = client->debug_data; + + kref_get(&debug_data->refcount); + + spin_lock(&debug_data->lock); + debug_data->stats_count = 0; + debug_data->stats_was_read = false; + spin_unlock(&debug_data->lock); + + file->private_data = debug_data; + + return 0; +} + +static void smsdvb_debugfs_data_release(struct kref *ref) +{ + struct smsdvb_debugfs *debug_data; + + debug_data = container_of(ref, struct smsdvb_debugfs, refcount); + kfree(debug_data); +} + +static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data) +{ + int rc = 1; + + spin_lock(&debug_data->lock); + + if (debug_data->stats_was_read) + goto exit; + + rc = debug_data->stats_count; + +exit: + spin_unlock(&debug_data->lock); + return rc; +} + +static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait) +{ + struct smsdvb_debugfs *debug_data = file->private_data; + int rc; + + kref_get(&debug_data->refcount); + + poll_wait(file, &debug_data->stats_queue, wait); + + rc = smsdvb_stats_wait_read(debug_data); + if (rc > 0) + rc = POLLIN | POLLRDNORM; + + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); + + return rc; +} + +static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) +{ + int rc = 0, len; + struct smsdvb_debugfs *debug_data = file->private_data; + + kref_get(&debug_data->refcount); + + if (file->f_flags & O_NONBLOCK) { + rc = smsdvb_stats_wait_read(debug_data); + if (!rc) { + rc = -EWOULDBLOCK; + goto ret; + } + } else { + rc = wait_event_interruptible(debug_data->stats_queue, + smsdvb_stats_wait_read(debug_data)); + if (rc < 0) + goto ret; + } + + if (debug_data->stats_was_read) { + rc = 0; /* EOF */ + goto ret; + } + + len = debug_data->stats_count - *ppos; + if (len >= 0) + rc = simple_read_from_buffer(user_buf, nbytes, ppos, + debug_data->stats_data, len); + else + rc = 0; + + if (*ppos >= debug_data->stats_count) { + spin_lock(&debug_data->lock); + debug_data->stats_was_read = true; + spin_unlock(&debug_data->lock); + } +ret: + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); + return rc; +} + +static int smsdvb_stats_release(struct inode *inode, struct file *file) +{ + struct smsdvb_debugfs *debug_data = file->private_data; + + spin_lock(&debug_data->lock); + debug_data->stats_was_read = true; /* return EOF to read() */ + spin_unlock(&debug_data->lock); + wake_up_interruptible_sync(&debug_data->stats_queue); + + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); + file->private_data = NULL; + + return 0; +} + +static const struct file_operations debugfs_stats_ops = { + .open = smsdvb_stats_open, + .poll = smsdvb_stats_poll, + .read = smsdvb_stats_read, + .release = smsdvb_stats_release, + .llseek = generic_file_llseek, +}; + +/* + * Functions used by smsdvb, in order to create the interfaces + */ + +int smsdvb_debugfs_create(struct smsdvb_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + struct dentry *d; + struct smsdvb_debugfs *debug_data; + + if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) + return -ENODEV; + + client->debugfs = debugfs_create_dir(coredev->devpath, + smsdvb_debugfs_usb_root); + if (IS_ERR_OR_NULL(client->debugfs)) { + pr_info("Unable to create debugfs %s directory.\n", + coredev->devpath); + return -ENODEV; + } + + d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, + client, &debugfs_stats_ops); + if (!d) { + debugfs_remove(client->debugfs); + return -ENOMEM; + } + + debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); + if (!debug_data) + return -ENOMEM; + + client->debug_data = debug_data; + client->prt_dvb_stats = smsdvb_print_dvb_stats; + client->prt_isdb_stats = smsdvb_print_isdb_stats; + client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex; + + init_waitqueue_head(&debug_data->stats_queue); + spin_lock_init(&debug_data->lock); + kref_init(&debug_data->refcount); + + return 0; +} + +void smsdvb_debugfs_release(struct smsdvb_client_t *client) +{ + if (!client->debugfs) + return; + + client->prt_dvb_stats = NULL; + client->prt_isdb_stats = NULL; + client->prt_isdb_stats_ex = NULL; + + debugfs_remove_recursive(client->debugfs); + kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release); + + client->debug_data = NULL; + client->debugfs = NULL; +} + +int smsdvb_debugfs_register(void) +{ + struct dentry *d; + + /* + * FIXME: This was written to debug Siano USB devices. So, it creates + * the debugfs node under <debugfs>/usb. + * A similar logic would be needed for Siano sdio devices, but, in that + * case, usb_debug_root is not a good choice. + * + * Perhaps the right fix here would be to create another sysfs root + * node for sdio-based boards, but this may need some logic at sdio + * subsystem. + */ + d = debugfs_create_dir("smsdvb", usb_debug_root); + if (IS_ERR_OR_NULL(d)) { + sms_err("Couldn't create sysfs node for smsdvb"); + return PTR_ERR(d); + } else { + smsdvb_debugfs_usb_root = d; + } + return 0; +} + +void smsdvb_debugfs_unregister(void) +{ + debugfs_remove_recursive(smsdvb_debugfs_usb_root); + smsdvb_debugfs_usb_root = NULL; +} diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c new file mode 100644 index 00000000000..85151efdd94 --- /dev/null +++ b/drivers/media/common/siano/smsdvb-main.c @@ -0,0 +1,1232 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +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, see <http://www.gnu.org/licenses/>. + +****************************************************************/ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <asm/div64.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" +#include "sms-cards.h" + +#include "smsdvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct list_head g_smsdvb_clients; +static struct mutex g_smsdvb_clientslock; + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + + +static u32 sms_to_guard_interval_table[] = { + [0] = GUARD_INTERVAL_1_32, + [1] = GUARD_INTERVAL_1_16, + [2] = GUARD_INTERVAL_1_8, + [3] = GUARD_INTERVAL_1_4, +}; + +static u32 sms_to_code_rate_table[] = { + [0] = FEC_1_2, + [1] = FEC_2_3, + [2] = FEC_3_4, + [3] = FEC_5_6, + [4] = FEC_7_8, +}; + + +static u32 sms_to_hierarchy_table[] = { + [0] = HIERARCHY_NONE, + [1] = HIERARCHY_1, + [2] = HIERARCHY_2, + [3] = HIERARCHY_4, +}; + +static u32 sms_to_modulation_table[] = { + [0] = QPSK, + [1] = QAM_16, + [2] = QAM_64, + [3] = DQPSK, +}; + + +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { + + struct smscore_device_t *coredev = client->coredev; + switch (event) { + case DVB3_EVENT_INIT: + sms_debug("DVB3_EVENT_INIT"); + sms_board_event(coredev, BOARD_EVENT_BIND); + break; + case DVB3_EVENT_SLEEP: + sms_debug("DVB3_EVENT_SLEEP"); + sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); + break; + case DVB3_EVENT_HOTPLUG: + sms_debug("DVB3_EVENT_HOTPLUG"); + sms_board_event(coredev, BOARD_EVENT_POWER_INIT); + break; + case DVB3_EVENT_FE_LOCK: + if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { + client->event_fe_state = DVB3_EVENT_FE_LOCK; + sms_debug("DVB3_EVENT_FE_LOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_LOCK); + } + break; + case DVB3_EVENT_FE_UNLOCK: + if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { + client->event_fe_state = DVB3_EVENT_FE_UNLOCK; + sms_debug("DVB3_EVENT_FE_UNLOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); + } + break; + case DVB3_EVENT_UNC_OK: + if (client->event_unc_state != DVB3_EVENT_UNC_OK) { + client->event_unc_state = DVB3_EVENT_UNC_OK; + sms_debug("DVB3_EVENT_UNC_OK"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); + } + break; + case DVB3_EVENT_UNC_ERR: + if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { + client->event_unc_state = DVB3_EVENT_UNC_ERR; + sms_debug("DVB3_EVENT_UNC_ERR"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); + } + break; + + default: + sms_err("Unknown dvb3 api event"); + break; + } +} + +static void smsdvb_stats_not_ready(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int i, n_layers; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + n_layers = 4; + break; + default: + n_layers = 1; + } + + /* Global stats */ + c->strength.len = 1; + c->cnr.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + + /* Per-layer stats */ + c->post_bit_error.len = n_layers; + c->post_bit_count.len = n_layers; + c->block_error.len = n_layers; + c->block_count.len = n_layers; + + /* + * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically + * changed when the stats become available. + */ + for (i = 0; i < n_layers; i++) { + c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + } +} + +static inline int sms_to_mode(u32 mode) +{ + switch (mode) { + case 2: + return TRANSMISSION_MODE_2K; + case 4: + return TRANSMISSION_MODE_4K; + case 8: + return TRANSMISSION_MODE_8K; + } + return TRANSMISSION_MODE_AUTO; +} + +static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) +{ + if (is_demod_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + + if (is_rf_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER; + + return 0; +} + +static inline u32 sms_to_bw(u32 value) +{ + return value * 1000000; +} + +#define convert_from_table(value, table, defval) ({ \ + u32 __ret; \ + if (value < ARRAY_SIZE(table)) \ + __ret = table[value]; \ + else \ + __ret = defval; \ + __ret; \ +}) + +#define sms_to_guard_interval(value) \ + convert_from_table(value, sms_to_guard_interval_table, \ + GUARD_INTERVAL_AUTO); + +#define sms_to_code_rate(value) \ + convert_from_table(value, sms_to_code_rate_table, \ + FEC_NONE); + +#define sms_to_hierarchy(value) \ + convert_from_table(value, sms_to_hierarchy_table, \ + FEC_NONE); + +#define sms_to_modulation(value) \ + convert_from_table(value, sms_to_modulation_table, \ + FEC_NONE); + +static void smsdvb_update_tx_params(struct smsdvb_client_t *client, + struct sms_tx_stats *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->code_rate_HP = sms_to_code_rate(p->code_rate); + c->code_rate_LP = sms_to_code_rate(p->lp_code_rate); + c->hierarchy = sms_to_hierarchy(p->hierarchy); + c->modulation = sms_to_modulation(p->constellation); +} + +static void smsdvb_update_per_slices(struct smsdvb_client_t *client, + struct RECEPTION_STATISTICS_PER_SLICES_S *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u64 tmp; + + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); + c->modulation = sms_to_modulation(p->constellation); + + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_power * 1000; + + /* Carrier to noise ratio, in DB */ + c->cnr.stat[0].svalue = p->snr * 1000; + + /* PER/BER requires demod lock */ + if (!p->is_demod_locked) + return; + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->ets_packets; + c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets; + + /* ber */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->ber_error_count; + c->post_bit_count.stat[0].uvalue += p->ber_bit_count; + + /* Legacy PER/BER */ + tmp = p->ets_packets * 65535; + if (p->ts_packets + p->ets_packets) + do_div(tmp, p->ts_packets + p->ets_packets); + client->legacy_per = tmp; +} + +static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, + struct sms_stats *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (client->prt_dvb_stats) + client->prt_dvb_stats(client->debug_data, p); + + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); + + /* Update DVB modulation parameters */ + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->code_rate_HP = sms_to_code_rate(p->code_rate); + c->code_rate_LP = sms_to_code_rate(p->lp_code_rate); + c->hierarchy = sms_to_hierarchy(p->hierarchy); + c->modulation = sms_to_modulation(p->constellation); + + /* update reception data */ + c->lna = p->is_external_lna_on ? 1 : 0; + + /* Carrier to noise ratio, in DB */ + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; + + /* PER/BER requires demod lock */ + if (!p->is_demod_locked) + return; + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->error_ts_packets; + c->block_count.stat[0].uvalue += p->total_ts_packets; + + /* ber */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->ber_error_count; + c->post_bit_count.stat[0].uvalue += p->ber_bit_count; + + /* Legacy PER/BER */ + client->legacy_ber = p->ber; +}; + +static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, + struct sms_isdbt_stats *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct sms_isdbt_layer_stats *lr; + int i, n_layers; + + if (client->prt_isdb_stats) + client->prt_isdb_stats(client->debug_data, p); + + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); + + /* + * Firmware 2.1 seems to report only lock status and + * signal strength. The signal strength indicator is at the + * wrong field. + */ + if (p->statistics_type == 0) { + c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + /* Update ISDB-T transmission parameters */ + c->frequency = p->frequency; + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->isdbt_partial_reception = p->partial_reception ? 1 : 0; + n_layers = p->num_of_layers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + + /* update reception data */ + c->lna = p->is_external_lna_on ? 1 : 0; + + /* Carrier to noise ratio, in DB */ + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; + + /* PER/BER and per-layer stats require demod lock */ + if (!p->is_demod_locked) + return; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + + for (i = 0; i < n_layers; i++) { + lr = &p->layer_info[i]; + + /* Update per-layer transmission parameters */ + if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->number_of_segments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->constellation); + + /* TS PER */ + c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_error.stat[i + 1].uvalue += lr->error_ts_packets; + c->block_count.stat[i + 1].uvalue += lr->total_ts_packets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->error_ts_packets; + c->block_count.stat[0].uvalue += lr->total_ts_packets; + + /* BER */ + c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count; + c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count; + + /* Update global BER counter */ + c->post_bit_error.stat[0].uvalue += lr->ber_error_count; + c->post_bit_count.stat[0].uvalue += lr->ber_bit_count; + } +} + +static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, + struct sms_isdbt_stats_ex *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct sms_isdbt_layer_stats *lr; + int i, n_layers; + + if (client->prt_isdb_stats_ex) + client->prt_isdb_stats_ex(client->debug_data, p); + + /* Update ISDB-T transmission parameters */ + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->isdbt_partial_reception = p->partial_reception ? 1 : 0; + n_layers = p->num_of_layers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + + /* update reception data */ + c->lna = p->is_external_lna_on ? 1 : 0; + + /* Carrier to noise ratio, in DB */ + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; + + /* PER/BER and per-layer stats require demod lock */ + if (!p->is_demod_locked) + return; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + + c->post_bit_error.len = n_layers + 1; + c->post_bit_count.len = n_layers + 1; + c->block_error.len = n_layers + 1; + c->block_count.len = n_layers + 1; + for (i = 0; i < n_layers; i++) { + lr = &p->layer_info[i]; + + /* Update per-layer transmission parameters */ + if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->number_of_segments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->constellation); + + /* TS PER */ + c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_error.stat[i + 1].uvalue += lr->error_ts_packets; + c->block_count.stat[i + 1].uvalue += lr->total_ts_packets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->error_ts_packets; + c->block_count.stat[0].uvalue += lr->total_ts_packets; + + /* ber */ + c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count; + c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count; + + /* Update global ber counter */ + c->post_bit_error.stat[0].uvalue += lr->ber_error_count; + c->post_bit_count.stat[0].uvalue += lr->ber_bit_count; + } +} + +static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) +{ + struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p) + + cb->offset); + void *p = phdr + 1; + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + bool is_status_update = false; + + switch (phdr->msg_type) { + case MSG_SMS_DVBT_BDA_DATA: + /* + * Only feed data to dvb demux if are there any feed listening + * to it and if the device has tuned + */ + if (client->feed_users && client->has_tuned) + dvb_dmx_swfilter(&client->demux, p, + cb->size - sizeof(struct sms_msg_hdr)); + break; + + case MSG_SMS_RF_TUNE_RES: + case MSG_SMS_ISDBT_TUNE_RES: + complete(&client->tune_done); + break; + + case MSG_SMS_SIGNAL_DETECTED_IND: + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + + is_status_update = true; + break; + + case MSG_SMS_NO_SIGNAL_IND: + client->fe_status = 0; + + is_status_update = true; + break; + + case MSG_SMS_TRANSMISSION_IND: + smsdvb_update_tx_params(client, p); + + is_status_update = true; + break; + + case MSG_SMS_HO_PER_SLICES_IND: + smsdvb_update_per_slices(client, p); + + is_status_update = true; + break; + + case MSG_SMS_GET_STATISTICS_RES: + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_update_isdbt_stats(client, p); + break; + default: + /* Skip sms_msg_statistics_info:request_result field */ + smsdvb_update_dvb_stats(client, p + sizeof(u32)); + } + + is_status_update = true; + break; + + /* Only for ISDB-T */ + case MSG_SMS_GET_STATISTICS_EX_RES: + /* Skip sms_msg_statistics_info:request_result field? */ + smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32)); + is_status_update = true; + break; + default: + sms_info("message not handled"); + } + smscore_putbuffer(client->coredev, cb); + + if (is_status_update) { + if (client->fe_status & FE_HAS_LOCK) { + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->last_per == c->block_error.stat[0].uvalue) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR); + client->has_tuned = true; + } else { + smsdvb_stats_not_ready(fe); + client->has_tuned = false; + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + complete(&client->stats_done); + } + + return 0; +} + +static void smsdvb_unregister_client(struct smsdvb_client_t *client) +{ + /* must be called under clientslock */ + + list_del(&client->entry); + + smsdvb_debugfs_release(client); + smscore_unregister_client(client->smsclient); + dvb_unregister_frontend(&client->frontend); + dvb_dmxdev_release(&client->dmxdev); + dvb_dmx_release(&client->demux); + dvb_unregister_adapter(&client->adapter); + kfree(client); +} + +static void smsdvb_onremove(void *context) +{ + kmutex_lock(&g_smsdvb_clientslock); + + smsdvb_unregister_client((struct smsdvb_client_t *) context); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +static int smsdvb_start_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct sms_msg_data pid_msg; + + sms_debug("add pid %d(%x)", + feed->pid, feed->pid); + + client->feed_users++; + + pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pid_msg.x_msg_header.msg_dst_id = HIF_TASK; + pid_msg.x_msg_header.msg_flags = 0; + pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; + pid_msg.x_msg_header.msg_length = sizeof(pid_msg); + pid_msg.msg_data[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &pid_msg, sizeof(pid_msg)); +} + +static int smsdvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct sms_msg_data pid_msg; + + sms_debug("remove pid %d(%x)", + feed->pid, feed->pid); + + client->feed_users--; + + pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pid_msg.x_msg_header.msg_dst_id = HIF_TASK; + pid_msg.x_msg_header.msg_flags = 0; + pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; + pid_msg.x_msg_header.msg_length = sizeof(pid_msg); + pid_msg.msg_data[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &pid_msg, sizeof(pid_msg)); +} + +static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, + void *buffer, size_t size, + struct completion *completion) +{ + int rc; + + rc = smsclient_sendrequest(client->smsclient, buffer, size); + if (rc < 0) + return rc; + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(2000)) ? + 0 : -ETIME; +} + +static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) +{ + int rc; + struct sms_msg_hdr msg; + + /* Don't request stats too fast */ + if (client->get_stats_jiffies && + (!time_after(jiffies, client->get_stats_jiffies))) + return 0; + client->get_stats_jiffies = jiffies + msecs_to_jiffies(100); + + msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg_dst_id = HIF_TASK; + msg.msg_flags = 0; + msg.msg_length = sizeof(msg); + + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + /* + * Check for firmware version, to avoid breaking for old cards + */ + if (client->coredev->fw_version >= 0x800) + msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ; + else + msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; + break; + default: + msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; + } + + rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), + &client->stats_done); + + return rc; +} + +static inline int led_feedback(struct smsdvb_client_t *client) +{ + if (!(client->fe_status & FE_HAS_LOCK)) + return sms_board_led_feedback(client->coredev, SMS_LED_OFF); + + return sms_board_led_feedback(client->coredev, + (client->legacy_ber == 0) ? + SMS_LED_HI : SMS_LED_LO); +} + +static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *stat = client->fe_status; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int rc; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ber = client->legacy_ber; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc; + s32 power = (s32) c->strength.stat[0].uvalue; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + if (power < -95) + *strength = 0; + else if (power > -29) + *strength = 65535; + else + *strength = (power + 95) * 65535 / 66; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + /* Preferred scale for SNR with legacy API: 0.1 dB */ + *snr = ((u32)c->cnr.stat[0].svalue) / 100; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int rc; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ucblocks = c->block_error.stat[0].uvalue; + + led_feedback(client); + + return rc; +} + +static int smsdvb_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + sms_debug(""); + + tune->min_delay_ms = 400; + tune->step_size = 250000; + tune->max_drift = 0; + return 0; +} + +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct sms_msg_hdr msg; + u32 Data[3]; + } msg; + + int ret; + + client->fe_status = 0; + client->event_fe_state = -1; + client->event_unc_state = -1; + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg.msg_dst_id = HIF_TASK; + msg.msg.msg_flags = 0; + msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ; + msg.msg.msg_length = sizeof(msg); + msg.Data[0] = c->frequency; + msg.Data[2] = 12000000; + + sms_info("%s: freq %d band %d", __func__, c->frequency, + c->bandwidth_hz); + + switch (c->bandwidth_hz / 1000000) { + case 8: + msg.Data[1] = BW_8_MHZ; + break; + case 7: + msg.Data[1] = BW_7_MHZ; + break; + case 6: + msg.Data[1] = BW_6_MHZ; + break; + case 0: + return -EOPNOTSUPP; + default: + return -EINVAL; + } + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + + return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), + &client->tune_done); +} + +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int board_id = smscore_get_board_id(client->coredev); + struct sms_board *board = sms_get_board(board_id); + enum sms_device_type_st type = board->type; + int ret; + + struct { + struct sms_msg_hdr msg; + u32 Data[4]; + } msg; + + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg.msg_dst_id = HIF_TASK; + msg.msg.msg_flags = 0; + msg.msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ; + msg.msg.msg_length = sizeof(msg); + + if (c->isdbt_sb_segment_idx == -1) + c->isdbt_sb_segment_idx = 0; + + if (!c->isdbt_layer_enabled) + c->isdbt_layer_enabled = 7; + + msg.Data[0] = c->frequency; + msg.Data[1] = BW_ISDBT_1SEG; + msg.Data[2] = 12000000; + msg.Data[3] = c->isdbt_sb_segment_idx; + + if (c->isdbt_partial_reception) { + if ((type == SMS_PELE || type == SMS_RIO) && + c->isdbt_sb_segment_count > 3) + msg.Data[1] = BW_ISDBT_13SEG; + else if (c->isdbt_sb_segment_count > 1) + msg.Data[1] = BW_ISDBT_3SEG; + } else if (type == SMS_PELE || type == SMS_RIO) + msg.Data[1] = BW_ISDBT_13SEG; + + c->bandwidth_hz = 6000000; + + sms_info("%s: freq %d segwidth %d segindex %d", __func__, + c->frequency, c->isdbt_sb_segment_count, + c->isdbt_sb_segment_idx); + + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), + &client->tune_done); +} + +static int smsdvb_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + + smsdvb_stats_not_ready(fe); + c->strength.stat[0].uvalue = 0; + c->cnr.stat[0].uvalue = 0; + + client->has_tuned = false; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + return smsdvb_dvbt_set_frontend(fe); + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + return smsdvb_isdbt_set_frontend(fe); + default: + return -EINVAL; + } +} + +/* Nothing to do here, as stats are automatically updated */ +static int smsdvb_get_frontend(struct dvb_frontend *fe) +{ + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + sms_board_dvb3_event(client, DVB3_EVENT_INIT); + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); + + return 0; +} + +static void smsdvb_release(struct dvb_frontend *fe) +{ + /* do nothing */ +} + +static struct dvb_frontend_ops smsdvb_fe_ops = { + .info = { + .name = "Siano Mobile Digital MDTV Receiver", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = smsdvb_release, + + .set_frontend = smsdvb_set_frontend, + .get_frontend = smsdvb_get_frontend, + .get_tune_settings = smsdvb_get_tune_settings, + + .read_status = smsdvb_read_status, + .read_ber = smsdvb_read_ber, + .read_signal_strength = smsdvb_read_signal_strength, + .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, +}; + +static int smsdvb_hotplug(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smsclient_params_t params; + struct smsdvb_client_t *client; + int rc; + + /* device removal handled by onremove callback */ + if (!arrival) + return 0; + client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); + if (!client) { + sms_err("kmalloc() failed"); + return -ENOMEM; + } + + /* register dvb adapter */ + rc = dvb_register_adapter(&client->adapter, + sms_get_board( + smscore_get_board_id(coredev))->name, + THIS_MODULE, device, adapter_nr); + if (rc < 0) { + sms_err("dvb_register_adapter() failed %d", rc); + goto adapter_error; + } + + /* init dvb demux */ + client->demux.dmx.capabilities = DMX_TS_FILTERING; + client->demux.filternum = 32; /* todo: nova ??? */ + client->demux.feednum = 32; + client->demux.start_feed = smsdvb_start_feed; + client->demux.stop_feed = smsdvb_stop_feed; + + rc = dvb_dmx_init(&client->demux); + if (rc < 0) { + sms_err("dvb_dmx_init failed %d", rc); + goto dvbdmx_error; + } + + /* init dmxdev */ + client->dmxdev.filternum = 32; + client->dmxdev.demux = &client->demux.dmx; + client->dmxdev.capabilities = 0; + + rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); + if (rc < 0) { + sms_err("dvb_dmxdev_init failed %d", rc); + goto dmxdev_error; + } + + /* init and register frontend */ + memcpy(&client->frontend.ops, &smsdvb_fe_ops, + sizeof(struct dvb_frontend_ops)); + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + client->frontend.ops.delsys[0] = SYS_DVBT; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + client->frontend.ops.delsys[0] = SYS_ISDBT; + break; + } + + rc = dvb_register_frontend(&client->adapter, &client->frontend); + if (rc < 0) { + sms_err("frontend registration failed %d", rc); + goto frontend_error; + } + + params.initial_id = 1; + params.data_type = MSG_SMS_DVBT_BDA_DATA; + params.onresponse_handler = smsdvb_onresponse; + params.onremove_handler = smsdvb_onremove; + params.context = client; + + rc = smscore_register_client(coredev, ¶ms, &client->smsclient); + if (rc < 0) { + sms_err("smscore_register_client() failed %d", rc); + goto client_error; + } + + client->coredev = coredev; + + init_completion(&client->tune_done); + init_completion(&client->stats_done); + + kmutex_lock(&g_smsdvb_clientslock); + + list_add(&client->entry, &g_smsdvb_clients); + + kmutex_unlock(&g_smsdvb_clientslock); + + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + + sms_info("success"); + sms_board_setup(coredev); + + if (smsdvb_debugfs_create(client) < 0) + sms_info("failed to create debugfs node"); + + return 0; + +client_error: + dvb_unregister_frontend(&client->frontend); + +frontend_error: + dvb_dmxdev_release(&client->dmxdev); + +dmxdev_error: + dvb_dmx_release(&client->demux); + +dvbdmx_error: + dvb_unregister_adapter(&client->adapter); + +adapter_error: + kfree(client); + return rc; +} + +static int __init smsdvb_module_init(void) +{ + int rc; + + INIT_LIST_HEAD(&g_smsdvb_clients); + kmutex_init(&g_smsdvb_clientslock); + + smsdvb_debugfs_register(); + + rc = smscore_register_hotplug(smsdvb_hotplug); + + sms_debug(""); + + return rc; +} + +static void __exit smsdvb_module_exit(void) +{ + smscore_unregister_hotplug(smsdvb_hotplug); + + kmutex_lock(&g_smsdvb_clientslock); + + while (!list_empty(&g_smsdvb_clients)) + smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next); + + smsdvb_debugfs_unregister(); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +module_init(smsdvb_module_init); +module_exit(smsdvb_module_exit); + +MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c deleted file mode 100644 index aa77e54a8fa..00000000000 --- a/drivers/media/common/siano/smsdvb.c +++ /dev/null @@ -1,1078 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik - -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, see <http://www.gnu.org/licenses/>. - -****************************************************************/ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" - -#include "smscoreapi.h" -#include "smsendian.h" -#include "sms-cards.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct smsdvb_client_t { - struct list_head entry; - - struct smscore_device_t *coredev; - struct smscore_client_t *smsclient; - - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dvb_frontend frontend; - - fe_status_t fe_status; - - struct completion tune_done; - - struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; - int event_fe_state; - int event_unc_state; -}; - -static struct list_head g_smsdvb_clients; -static struct mutex g_smsdvb_clientslock; - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -/* Events that may come from DVB v3 adapter */ -static void sms_board_dvb3_event(struct smsdvb_client_t *client, - enum SMS_DVB3_EVENTS event) { - - struct smscore_device_t *coredev = client->coredev; - switch (event) { - case DVB3_EVENT_INIT: - sms_debug("DVB3_EVENT_INIT"); - sms_board_event(coredev, BOARD_EVENT_BIND); - break; - case DVB3_EVENT_SLEEP: - sms_debug("DVB3_EVENT_SLEEP"); - sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); - break; - case DVB3_EVENT_HOTPLUG: - sms_debug("DVB3_EVENT_HOTPLUG"); - sms_board_event(coredev, BOARD_EVENT_POWER_INIT); - break; - case DVB3_EVENT_FE_LOCK: - if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { - client->event_fe_state = DVB3_EVENT_FE_LOCK; - sms_debug("DVB3_EVENT_FE_LOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_LOCK); - } - break; - case DVB3_EVENT_FE_UNLOCK: - if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { - client->event_fe_state = DVB3_EVENT_FE_UNLOCK; - sms_debug("DVB3_EVENT_FE_UNLOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); - } - break; - case DVB3_EVENT_UNC_OK: - if (client->event_unc_state != DVB3_EVENT_UNC_OK) { - client->event_unc_state = DVB3_EVENT_UNC_OK; - sms_debug("DVB3_EVENT_UNC_OK"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); - } - break; - case DVB3_EVENT_UNC_ERR: - if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { - client->event_unc_state = DVB3_EVENT_UNC_ERR; - sms_debug("DVB3_EVENT_UNC_ERR"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); - } - break; - - default: - sms_err("Unknown dvb3 api event"); - break; - } -} - - -static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ST *p) -{ - if (sms_dbg & 2) { - printk(KERN_DEBUG "Reserved = %d", p->Reserved); - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "BER = %d", p->BER); - printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); - printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); - printk(KERN_DEBUG "MFER = %d", p->MFER); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); - printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); - printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); - printk(KERN_DEBUG "Constellation = %d", p->Constellation); - printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); - printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); - printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); - printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); - printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); - printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); - printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); - printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); - printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); - printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); - printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); - printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); - printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); - printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - printk(KERN_DEBUG "PreBER = %d", p->PreBER); - printk(KERN_DEBUG "CellId = %d", p->CellId); - printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); - printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); - printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->BER; - pReceptionData->BERErrorCount = p->BERErrorCount; - pReceptionData->InBandPwr = p->InBandPwr; - pReceptionData->ErrorTSPackets = p->ErrorTSPackets; -}; - - -static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) -{ - int i; - - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); - } - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->InBandPwr = p->InBandPwr; - - pReceptionData->ErrorTSPackets = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - for (i = 0; i < 3; i++) { - pReceptionData->BER += p->LayerInfo[i].BER; - pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; - pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; - } -} - -static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) -{ - struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) - + cb->offset); - u32 *pMsgData = (u32 *) phdr + 1; - /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ - bool is_status_update = false; - - smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); - - switch (phdr->msgType) { - case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), - cb->size - sizeof(struct SmsMsgHdr_ST)); - break; - - case MSG_SMS_RF_TUNE_RES: - case MSG_SMS_ISDBT_TUNE_RES: - complete(&client->tune_done); - break; - - case MSG_SMS_SIGNAL_DETECTED_IND: - sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; - is_status_update = true; - break; - - case MSG_SMS_NO_SIGNAL_IND: - sms_info("MSG_SMS_NO_SIGNAL_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; - is_status_update = true; - break; - - case MSG_SMS_TRANSMISSION_IND: { - sms_info("MSG_SMS_TRANSMISSION_IND"); - - pMsgData++; - memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, - sizeof(struct TRANSMISSION_STATISTICS_S)); - - /* Mo need to correct guard interval - * (as opposed to old statistics message). - */ - CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); - CORRECT_STAT_TRANSMISSON_MODE( - client->sms_stat_dvb.TransmissionData); - is_status_update = true; - break; - } - case MSG_SMS_HO_PER_SLICES_IND: { - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - struct SRVM_SIGNAL_STATUS_S SignalStatusData; - - /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ - pMsgData++; - SignalStatusData.result = pMsgData[0]; - SignalStatusData.snr = pMsgData[1]; - SignalStatusData.inBandPower = (s32) pMsgData[2]; - SignalStatusData.tsPackets = pMsgData[3]; - SignalStatusData.etsPackets = pMsgData[4]; - SignalStatusData.constellation = pMsgData[5]; - SignalStatusData.hpCode = pMsgData[6]; - SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; - SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; - SignalStatusData.cellId = pMsgData[9] & 0xFFFF; - SignalStatusData.reason = pMsgData[10]; - SignalStatusData.requestId = pMsgData[11]; - pReceptionData->IsRfLocked = pMsgData[16]; - pReceptionData->IsDemodLocked = pMsgData[17]; - pReceptionData->ModemState = pMsgData[12]; - pReceptionData->SNR = pMsgData[1]; - pReceptionData->BER = pMsgData[13]; - pReceptionData->RSSI = pMsgData[14]; - CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); - - pReceptionData->InBandPwr = (s32) pMsgData[2]; - pReceptionData->CarrierOffset = (s32) pMsgData[15]; - pReceptionData->TotalTSPackets = pMsgData[3]; - pReceptionData->ErrorTSPackets = pMsgData[4]; - - /* TS PER */ - if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) - > 0) { - pReceptionData->TS_PER = (SignalStatusData.etsPackets - * 100) / (SignalStatusData.tsPackets - + SignalStatusData.etsPackets); - } else { - pReceptionData->TS_PER = 0; - } - - pReceptionData->BERBitCount = pMsgData[18]; - pReceptionData->BERErrorCount = pMsgData[19]; - - pReceptionData->MRC_SNR = pMsgData[20]; - pReceptionData->MRC_InBandPwr = pMsgData[21]; - pReceptionData->MRC_RSSI = pMsgData[22]; - - is_status_update = true; - break; - } - case MSG_SMS_GET_STATISTICS_RES: { - union { - struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; - struct SmsMsgStatisticsInfo_ST dvb; - } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - - sms_info("MSG_SMS_GET_STATISTICS_RES"); - - is_status_update = true; - - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); - break; - default: - smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); - } - if (!pReceptionData->IsDemodLocked) { - pReceptionData->SNR = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - pReceptionData->InBandPwr = 0; - pReceptionData->ErrorTSPackets = 0; - } - - complete(&client->tune_done); - break; - } - default: - sms_info("Unhandled message %d", phdr->msgType); - - } - smscore_putbuffer(client->coredev, cb); - - if (is_status_update) { - if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); - if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets - == 0) - sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); - else - sms_board_dvb3_event(client, - DVB3_EVENT_UNC_ERR); - - } else { - if (client->sms_stat_dvb.ReceptionData.IsRfLocked) - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - client->fe_status = 0; - sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); - } - } - - return 0; -} - -static void smsdvb_unregister_client(struct smsdvb_client_t *client) -{ - /* must be called under clientslock */ - - list_del(&client->entry); - - smscore_unregister_client(client->smsclient); - dvb_unregister_frontend(&client->frontend); - dvb_dmxdev_release(&client->dmxdev); - dvb_dmx_release(&client->demux); - dvb_unregister_adapter(&client->adapter); - kfree(client); -} - -static void smsdvb_onremove(void *context) -{ - kmutex_lock(&g_smsdvb_clientslock); - - smsdvb_unregister_client((struct smsdvb_client_t *) context); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -static int smsdvb_start_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("add pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("remove pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, - void *buffer, size_t size, - struct completion *completion) -{ - int rc; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); - rc = smsclient_sendrequest(client->smsclient, buffer, size); - if (rc < 0) - return rc; - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(2000)) ? - 0 : -ETIME; -} - -static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) -{ - int rc; - struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, - DVBT_BDA_CONTROL_MSG_ID, - HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; - - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - return rc; -} - -static inline int led_feedback(struct smsdvb_client_t *client) -{ - if (client->fe_status & FE_HAS_LOCK) - return sms_board_led_feedback(client->coredev, - (client->sms_stat_dvb.ReceptionData.BER - == 0) ? SMS_LED_HI : SMS_LED_LO); - else - return sms_board_led_feedback(client->coredev, SMS_LED_OFF); -} - -static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *stat = client->fe_status; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ber = client->sms_stat_dvb.ReceptionData.BER; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - int rc; - - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) - *strength = 0; - else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) - *strength = 100; - else - *strength = - (client->sms_stat_dvb.ReceptionData.InBandPwr - + 95) * 3 / 2; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *snr = client->sms_stat_dvb.ReceptionData.SNR; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; - - led_feedback(client); - - return rc; -} - -static int smsdvb_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - sms_debug(""); - - tune->min_delay_ms = 400; - tune->step_size = 250000; - tune->max_drift = 0; - return 0; -} - -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[3]; - } Msg; - - int ret; - - client->fe_status = FE_HAS_SIGNAL; - client->event_fe_state = -1; - client->event_unc_state = -1; - fe->dtv_property_cache.delivery_system = SYS_DVBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - - sms_info("%s: freq %d band %d", __func__, c->frequency, - c->bandwidth_hz); - - switch (c->bandwidth_hz / 1000000) { - case 8: - Msg.Data[1] = BW_8_MHZ; - break; - case 7: - Msg.Data[1] = BW_7_MHZ; - break; - case 6: - Msg.Data[1] = BW_6_MHZ; - break; - case 0: - return -EOPNOTSUPP; - default: - return -EINVAL; - } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didn't lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[4]; - } Msg; - - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - - if (c->isdbt_sb_segment_idx == -1) - c->isdbt_sb_segment_idx = 0; - - switch (c->isdbt_sb_segment_count) { - case 3: - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 1: - Msg.Data[1] = BW_ISDBT_1SEG; - break; - case 0: /* AUTO */ - switch (c->bandwidth_hz / 1000000) { - case 8: - case 7: - c->isdbt_sb_segment_count = 3; - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 6: - c->isdbt_sb_segment_count = 1; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - default: /* Assumes 6 MHZ bw */ - c->isdbt_sb_segment_count = 1; - c->bandwidth_hz = 6000; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - } - break; - default: - sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); - return -EINVAL; - } - - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - Msg.Data[3] = c->isdbt_sb_segment_idx; - - sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, - c->frequency, c->isdbt_sb_segment_count, - c->isdbt_sb_segment_idx); - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_set_frontend(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe); - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe); - default: - return -EINVAL; - } -} - -static int smsdvb_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - struct TRANSMISSION_STATISTICS_S *td = - &client->sms_stat_dvb.TransmissionData; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - fep->frequency = td->Frequency; - - switch (td->Bandwidth) { - case 6: - fep->bandwidth_hz = 6000000; - break; - case 7: - fep->bandwidth_hz = 7000000; - break; - case 8: - fep->bandwidth_hz = 8000000; - break; - } - - switch (td->TransmissionMode) { - case 2: - fep->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 8: - fep->transmission_mode = TRANSMISSION_MODE_8K; - } - - switch (td->GuardInterval) { - case 0: - fep->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fep->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fep->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fep->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - switch (td->CodeRate) { - case 0: - fep->code_rate_HP = FEC_1_2; - break; - case 1: - fep->code_rate_HP = FEC_2_3; - break; - case 2: - fep->code_rate_HP = FEC_3_4; - break; - case 3: - fep->code_rate_HP = FEC_5_6; - break; - case 4: - fep->code_rate_HP = FEC_7_8; - break; - } - - switch (td->LPCodeRate) { - case 0: - fep->code_rate_LP = FEC_1_2; - break; - case 1: - fep->code_rate_LP = FEC_2_3; - break; - case 2: - fep->code_rate_LP = FEC_3_4; - break; - case 3: - fep->code_rate_LP = FEC_5_6; - break; - case 4: - fep->code_rate_LP = FEC_7_8; - break; - } - - switch (td->Constellation) { - case 0: - fep->modulation = QPSK; - break; - case 1: - fep->modulation = QAM_16; - break; - case 2: - fep->modulation = QAM_64; - break; - } - - switch (td->Hierarchy) { - case 0: - fep->hierarchy = HIERARCHY_NONE; - break; - case 1: - fep->hierarchy = HIERARCHY_1; - break; - case 2: - fep->hierarchy = HIERARCHY_2; - break; - case 3: - fep->hierarchy = HIERARCHY_4; - break; - } - - fep->inversion = INVERSION_AUTO; - break; - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - fep->frequency = td->Frequency; - fep->bandwidth_hz = 6000000; - /* todo: retrive the other parameters */ - break; - default: - return -EINVAL; - } - - return 0; -} - -static int smsdvb_init(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_power(client->coredev, 1); - - sms_board_dvb3_event(client, DVB3_EVENT_INIT); - return 0; -} - -static int smsdvb_sleep(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); - - sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); - - return 0; -} - -static void smsdvb_release(struct dvb_frontend *fe) -{ - /* do nothing */ -} - -static struct dvb_frontend_ops smsdvb_fe_ops = { - .info = { - .name = "Siano Mobile Digital MDTV Receiver", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = smsdvb_release, - - .set_frontend = smsdvb_set_frontend, - .get_frontend = smsdvb_get_frontend, - .get_tune_settings = smsdvb_get_tune_settings, - - .read_status = smsdvb_read_status, - .read_ber = smsdvb_read_ber, - .read_signal_strength = smsdvb_read_signal_strength, - .read_snr = smsdvb_read_snr, - .read_ucblocks = smsdvb_read_ucblocks, - - .init = smsdvb_init, - .sleep = smsdvb_sleep, -}; - -static int smsdvb_hotplug(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct smsclient_params_t params; - struct smsdvb_client_t *client; - int rc; - - /* device removal handled by onremove callback */ - if (!arrival) - return 0; - client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); - if (!client) { - sms_err("kmalloc() failed"); - return -ENOMEM; - } - - /* register dvb adapter */ - rc = dvb_register_adapter(&client->adapter, - sms_get_board( - smscore_get_board_id(coredev))->name, - THIS_MODULE, device, adapter_nr); - if (rc < 0) { - sms_err("dvb_register_adapter() failed %d", rc); - goto adapter_error; - } - - /* init dvb demux */ - client->demux.dmx.capabilities = DMX_TS_FILTERING; - client->demux.filternum = 32; /* todo: nova ??? */ - client->demux.feednum = 32; - client->demux.start_feed = smsdvb_start_feed; - client->demux.stop_feed = smsdvb_stop_feed; - - rc = dvb_dmx_init(&client->demux); - if (rc < 0) { - sms_err("dvb_dmx_init failed %d", rc); - goto dvbdmx_error; - } - - /* init dmxdev */ - client->dmxdev.filternum = 32; - client->dmxdev.demux = &client->demux.dmx; - client->dmxdev.capabilities = 0; - - rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); - if (rc < 0) { - sms_err("dvb_dmxdev_init failed %d", rc); - goto dmxdev_error; - } - - /* init and register frontend */ - memcpy(&client->frontend.ops, &smsdvb_fe_ops, - sizeof(struct dvb_frontend_ops)); - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - client->frontend.ops.delsys[0] = SYS_DVBT; - break; - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - client->frontend.ops.delsys[0] = SYS_ISDBT; - break; - } - - rc = dvb_register_frontend(&client->adapter, &client->frontend); - if (rc < 0) { - sms_err("frontend registration failed %d", rc); - goto frontend_error; - } - - params.initial_id = 1; - params.data_type = MSG_SMS_DVBT_BDA_DATA; - params.onresponse_handler = smsdvb_onresponse; - params.onremove_handler = smsdvb_onremove; - params.context = client; - - rc = smscore_register_client(coredev, ¶ms, &client->smsclient); - if (rc < 0) { - sms_err("smscore_register_client() failed %d", rc); - goto client_error; - } - - client->coredev = coredev; - - init_completion(&client->tune_done); - - kmutex_lock(&g_smsdvb_clientslock); - - list_add(&client->entry, &g_smsdvb_clients); - - kmutex_unlock(&g_smsdvb_clientslock); - - client->event_fe_state = -1; - client->event_unc_state = -1; - sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); - - sms_info("success"); - sms_board_setup(coredev); - - return 0; - -client_error: - dvb_unregister_frontend(&client->frontend); - -frontend_error: - dvb_dmxdev_release(&client->dmxdev); - -dmxdev_error: - dvb_dmx_release(&client->demux); - -dvbdmx_error: - dvb_unregister_adapter(&client->adapter); - -adapter_error: - kfree(client); - return rc; -} - -static int __init smsdvb_module_init(void) -{ - int rc; - - INIT_LIST_HEAD(&g_smsdvb_clients); - kmutex_init(&g_smsdvb_clientslock); - - rc = smscore_register_hotplug(smsdvb_hotplug); - - sms_debug(""); - - return rc; -} - -static void __exit smsdvb_module_exit(void) -{ - smscore_unregister_hotplug(smsdvb_hotplug); - - kmutex_lock(&g_smsdvb_clientslock); - - while (!list_empty(&g_smsdvb_clients)) - smsdvb_unregister_client( - (struct smsdvb_client_t *) g_smsdvb_clients.next); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -module_init(smsdvb_module_init); -module_exit(smsdvb_module_exit); - -MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h new file mode 100644 index 00000000000..ae36d0ae0fb --- /dev/null +++ b/drivers/media/common/siano/smsdvb.h @@ -0,0 +1,130 @@ +/*********************************************************************** + * + * 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, see <http://www.gnu.org/licenses/>. + * + ***********************************************************************/ + +struct smsdvb_debugfs; +struct smsdvb_client_t; + +typedef void (*sms_prt_dvb_stats_t)(struct smsdvb_debugfs *debug_data, + struct sms_stats *p); + +typedef void (*sms_prt_isdb_stats_t)(struct smsdvb_debugfs *debug_data, + struct sms_isdbt_stats *p); + +typedef void (*sms_prt_isdb_stats_ex_t) + (struct smsdvb_debugfs *debug_data, + struct sms_isdbt_stats_ex *p); + + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + + struct completion tune_done; + struct completion stats_done; + + int last_per; + + int legacy_ber, legacy_per; + + int event_fe_state; + int event_unc_state; + + unsigned long get_stats_jiffies; + + int feed_users; + bool has_tuned; + + /* stats debugfs data */ + struct dentry *debugfs; + + struct smsdvb_debugfs *debug_data; + + sms_prt_dvb_stats_t prt_dvb_stats; + sms_prt_isdb_stats_t prt_isdb_stats; + sms_prt_isdb_stats_ex_t prt_isdb_stats_ex; +}; + +/* + * This struct is a mix of struct sms_rx_stats_ex and + * struct sms_srvm_signal_status. + * It was obtained by comparing the way it was filled by the original code + */ +struct RECEPTION_STATISTICS_PER_SLICES_S { + u32 result; + u32 snr; + s32 in_band_power; + u32 ts_packets; + u32 ets_packets; + u32 constellation; + u32 hp_code; + u32 tps_srv_ind_lp; + u32 tps_srv_ind_hp; + u32 cell_id; + u32 reason; + u32 request_id; + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + + u32 ber; /* Post Viterbi BER [1E-5] */ + s32 RSSI; /* dBm */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ + + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + + u32 ber_bit_count; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of erroneous SYNC bits. */ + + s32 MRC_SNR; /* dB */ + s32 mrc_in_band_pwr; /* In band power in dBM */ + s32 MRC_RSSI; /* dBm */ +}; + +/* From smsdvb-debugfs.c */ +#ifdef CONFIG_SMS_SIANO_DEBUGFS + +int smsdvb_debugfs_create(struct smsdvb_client_t *client); +void smsdvb_debugfs_release(struct smsdvb_client_t *client); +int smsdvb_debugfs_register(void); +void smsdvb_debugfs_unregister(void); + +#else + +static inline int smsdvb_debugfs_create(struct smsdvb_client_t *client) +{ + return 0; +} + +static inline void smsdvb_debugfs_release(struct smsdvb_client_t *client) {} + +static inline int smsdvb_debugfs_register(void) +{ + return 0; +}; + +static inline void smsdvb_debugfs_unregister(void) {}; + +#endif + diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index e2657c2f010..bfe831c10b1 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -28,23 +28,23 @@ void smsendian_handle_tx_message(void *buffer) { #ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; - int msgWords; + int msg_words; - switch (msg->xMsgHeader.msgType) { + switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); break; } default: - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; + msg_words = (msg->x_msg_header.msg_length - + sizeof(struct sms_msg_hdr))/4; - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + for (i = 0; i < msg_words; i++) + msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); break; } @@ -55,16 +55,16 @@ EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); void smsendian_handle_rx_message(void *buffer) { #ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; - int msgWords; + int msg_words; - switch (msg->xMsgHeader.msgType) { + switch (msg->x_msg_header.msg_type) { case MSG_SMS_GET_VERSION_EX_RES: { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) msg; - ver->ChipModel = le16_to_cpu(ver->ChipModel); + struct sms_version_res *ver = + (struct sms_version_res *) msg; + ver->chip_model = le16_to_cpu(ver->chip_model); break; } @@ -77,11 +77,11 @@ void smsendian_handle_rx_message(void *buffer) default: { - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; + msg_words = (msg->x_msg_header.msg_length - + sizeof(struct sms_msg_hdr))/4; - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + for (i = 0; i < msg_words; i++) + msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); break; } @@ -93,11 +93,11 @@ EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); void smsendian_handle_message_header(void *msg) { #ifdef __BIG_ENDIAN - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msgType = le16_to_cpu(phdr->msgType); - phdr->msgLength = le16_to_cpu(phdr->msgLength); - phdr->msgFlags = le16_to_cpu(phdr->msgFlags); + phdr->msg_type = le16_to_cpu(phdr->msg_type); + phdr->msg_length = le16_to_cpu(phdr->msg_length); + phdr->msg_flags = le16_to_cpu(phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index 37bc5c4b8ad..6d7c0c858bd 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->priv = coredev; dev->driver_type = RC_DRIVER_IR_RAW; - dev->allowed_protos = RC_TYPE_ALL; + rc_set_allowed_protocols(dev, RC_BIT_ALL); dev->map_name = sms_get_board(board_id)->rc_codes; dev->driver_name = MODULE_NAME; diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index ae92b3a8587..fc8b7925c53 100644 --- a/drivers/media/common/siano/smsir.h +++ b/drivers/media/common/siano/smsir.h @@ -40,16 +40,24 @@ struct ir_t { char phys[32]; char *rc_codes; - u64 protocol; u32 timeout; u32 controller; }; +#ifdef CONFIG_SMS_SIANO_RC int sms_ir_init(struct smscore_device_t *coredev); void sms_ir_exit(struct smscore_device_t *coredev); void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len); +#else +inline static int sms_ir_init(struct smscore_device_t *coredev) { + return 0; +} +inline static void sms_ir_exit(struct smscore_device_t *coredev) {}; +inline static void sms_ir_event(struct smscore_device_t *coredev, + const char *buf, int len) {}; +#endif #endif /* __SMS_IR_H__ */ diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c new file mode 100644 index 00000000000..c7dace671a9 --- /dev/null +++ b/drivers/media/common/tveeprom.c @@ -0,0 +1,776 @@ +/* + * tveeprom - eeprom decoder for tvcard configuration eeproms + * + * Data and decoding routines shamelessly borrowed from bttv-cards.c + * eeprom access routine shamelessly borrowed from bttv-if.c + * which are: + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de> + + * Adjustments to fit a more general model and all bugs: + + Copyright (C) 2003 John Klar <linpvr at projectplasma.com> + + * 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/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/videodev2.h> +#include <linux/i2c.h> + +#include <media/tuner.h> +#include <media/tveeprom.h> +#include <media/v4l2-common.h> + +MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); +MODULE_AUTHOR("John Klar"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +#define STRM(array, i) \ + (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") + +#define tveeprom_info(fmt, arg...) \ + v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) +#define tveeprom_warn(fmt, arg...) \ + v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) +#define tveeprom_dbg(fmt, arg...) do { \ + if (debug) \ + v4l_printk(KERN_DEBUG, "tveeprom", \ + c->adapter, c->addr, fmt , ## arg); \ + } while (0) + +/* + * The Hauppauge eeprom uses an 8bit field to determine which + * tuner formats the tuner supports. + */ +static const struct { + int id; + const char * const name; +} hauppauge_tuner_fmt[] = { + { V4L2_STD_UNKNOWN, " UNKNOWN" }, + { V4L2_STD_UNKNOWN, " FM" }, + { V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" }, + { V4L2_STD_MN, " NTSC(M)" }, + { V4L2_STD_PAL_I, " PAL(I)" }, + { V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" }, + { V4L2_STD_DK, " PAL(D/D1/K)" }, + { V4L2_STD_ATSC, " ATSC/DVB Digital" }, +}; + +/* This is the full list of possible tuners. Many thanks to Hauppauge for + supplying this information. Note that many tuners where only used for + testing and never made it to the outside world. So you will only see + a subset in actual produced cards. */ +static const struct { + int id; + const char * const name; +} hauppauge_tuner[] = { + /* 0-9 */ + { TUNER_ABSENT, "None" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_PHILIPS_PAL, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + /* 10-19 */ + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, + { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + /* 20-29 */ + { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, + /* 30-39 */ + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, + { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, + { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ + { TUNER_ABSENT, "Philips FI1256MP" }, + /* 40-49 */ + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_TEMIC_4006FN5_MULTI_PAL,"Temic 4006FN5" }, + { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, + { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, + { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, + { TUNER_ABSENT, "Philips TD1536D FH 44"}, + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + /* 50-59 */ + { TUNER_LG_PAL_I, "LG TAPC-I701D"}, + { TUNER_ABSENT, "Temic 4042FI5"}, + { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, + { TUNER_ABSENT, "LG TPI8NSR11F"}, + { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, + { TUNER_ABSENT, "Philips FI1236 MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, + { TUNER_ABSENT, "Philips FM1216MP MK3"}, + /* 60-69 */ + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, + { TUNER_ABSENT, "LG M001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, + { TUNER_ABSENT, "LG M701D MK3"}, + { TUNER_ABSENT, "Temic 4146FM5"}, + { TUNER_ABSENT, "Temic 4136FY5"}, + { TUNER_ABSENT, "Temic 4106FH5"}, + { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, + /* 70-79 */ + { TUNER_ABSENT, "LG TALN H200T"}, + { TUNER_ABSENT, "LG TALN H250T"}, + { TUNER_ABSENT, "LG TALN M200T"}, + { TUNER_ABSENT, "LG TALN Z200T"}, + { TUNER_ABSENT, "LG TALN S200T"}, + { TUNER_ABSENT, "Thompson DTT7595"}, + { TUNER_ABSENT, "Thompson DTT7592"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, + { TUNER_ABSENT, "Thompson DTT757"}, + /* 80-89 */ + { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"}, + { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, + { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, + { TUNER_TCL_2002N, "TCL 2002N 6A"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, + { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, + { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, + /* 90-99 */ + { TUNER_ABSENT, "LG TALN H202T"}, + { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, + { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, + { TUNER_ABSENT, "Philips FQ1286A MK4"}, + { TUNER_ABSENT, "Philips FQ1216ME MK5"}, + { TUNER_ABSENT, "Philips FQ1236 MK5"}, + { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, + { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, + { TUNER_ABSENT, "TCL 2002MI_3H"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, + /* 100-109 */ + { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, + { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, + { TUNER_ABSENT, "Panasonic ENV57H12D5"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, + { TUNER_ABSENT, "TCL MQNM05-4"}, + { TUNER_ABSENT, "LG TAPC-W701D"}, + { TUNER_ABSENT, "TCL 9886P-WM"}, + { TUNER_ABSENT, "TCL 1676NM-WM"}, + /* 110-119 */ + { TUNER_ABSENT, "Thompson DTT75105"}, + { TUNER_ABSENT, "Conexant_CX24109"}, + { TUNER_TCL_2002N, "TCL M2523_5N_E"}, + { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, + { TUNER_ABSENT, "Philips 8275A"}, + { TUNER_ABSENT, "Microtune MT2060"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, + { TUNER_ABSENT, "TCL M2523_3DI_E"}, + { TUNER_ABSENT, "Samsung THPD5222FG30A"}, + /* 120-129 */ + { TUNER_XC2028, "Xceive XC3028"}, + { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"}, + { TUNER_ABSENT, "Philips FQD1216LME"}, + { TUNER_ABSENT, "Conexant CX24118A"}, + { TUNER_ABSENT, "TCL DMF11WIP"}, + { TUNER_ABSENT, "TCL MFNM05_4H_E"}, + { TUNER_ABSENT, "TCL MNM05_4H_E"}, + { TUNER_ABSENT, "TCL MPE05_2H_E"}, + { TUNER_ABSENT, "TCL MQNM05_4_U"}, + { TUNER_ABSENT, "TCL M2523_5NH_E"}, + /* 130-139 */ + { TUNER_ABSENT, "TCL M2523_3DBH_E"}, + { TUNER_ABSENT, "TCL M2523_3DIH_E"}, + { TUNER_ABSENT, "TCL MFPE05_2_U"}, + { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"}, + { TUNER_ABSENT, "Philips FRH2036B"}, + { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, + { TUNER_ABSENT, "MaxLinear MXL5005"}, + { TUNER_ABSENT, "MaxLinear MXL5003"}, + { TUNER_ABSENT, "Xceive XC2028"}, + { TUNER_ABSENT, "Microtune MT2131"}, + /* 140-149 */ + { TUNER_ABSENT, "Philips 8275A_8295"}, + { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, + { TUNER_ABSENT, "Microtune MT2266"}, + { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, + { TUNER_ABSENT, "LG TAPQ_H702F"}, + { TUNER_ABSENT, "TCL M09WPP_4N_E"}, + { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, + { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, + /* 150-159 */ + { TUNER_XC5000, "Xceive XC5000"}, + { TUNER_ABSENT, "Xceive XC3028L"}, + { TUNER_ABSENT, "NXP 18271C2_716x"}, + { TUNER_ABSENT, "Xceive XC4000"}, + { TUNER_ABSENT, "Dibcom 7070"}, + { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, + { TUNER_ABSENT, "Siano SMS1010"}, + { TUNER_ABSENT, "Siano SMS1150"}, + { TUNER_ABSENT, "MaxLinear 5007"}, + { TUNER_ABSENT, "TCL M09WPP_2P_E"}, + /* 160-169 */ + { TUNER_ABSENT, "Siano SMS1180"}, + { TUNER_ABSENT, "Maxim_MAX2165"}, + { TUNER_ABSENT, "Siano SMS1140"}, + { TUNER_ABSENT, "Siano SMS1150 B1"}, + { TUNER_ABSENT, "MaxLinear 111"}, + { TUNER_ABSENT, "Dibcom 7770"}, + { TUNER_ABSENT, "Siano SMS1180VNS"}, + { TUNER_ABSENT, "Siano SMS1184"}, + { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, + { TUNER_ABSENT, "TCL_M11WPP_2PN_E"}, + /* 170-179 */ + { TUNER_ABSENT, "MaxLinear 301"}, + { TUNER_ABSENT, "Mirics MSi001"}, + { TUNER_ABSENT, "MaxLinear MxL241SF"}, + { TUNER_XC5000C, "Xceive XC5000C"}, + { TUNER_ABSENT, "Montage M68TS2020"}, + { TUNER_ABSENT, "Siano SMS1530"}, + { TUNER_ABSENT, "Dibcom 7090"}, + { TUNER_ABSENT, "Xceive XC5200C"}, + { TUNER_ABSENT, "NXP 18273"}, + { TUNER_ABSENT, "Montage M88TS2022"}, + /* 180-189 */ + { TUNER_ABSENT, "NXP 18272M"}, + { TUNER_ABSENT, "NXP 18272S"}, +}; + +/* Use TVEEPROM_AUDPROC_INTERNAL for those audio 'chips' that are + * internal to a video chip, i.e. not a separate audio chip. */ +static const struct { + u32 id; + const char * const name; +} audio_ic[] = { + /* 0-4 */ + { TVEEPROM_AUDPROC_NONE, "None" }, + { TVEEPROM_AUDPROC_OTHER, "TEA6300" }, + { TVEEPROM_AUDPROC_OTHER, "TEA6320" }, + { TVEEPROM_AUDPROC_OTHER, "TDA9850" }, + { TVEEPROM_AUDPROC_MSP, "MSP3400C" }, + /* 5-9 */ + { TVEEPROM_AUDPROC_MSP, "MSP3410D" }, + { TVEEPROM_AUDPROC_MSP, "MSP3415" }, + { TVEEPROM_AUDPROC_MSP, "MSP3430" }, + { TVEEPROM_AUDPROC_MSP, "MSP3438" }, + { TVEEPROM_AUDPROC_OTHER, "CS5331" }, + /* 10-14 */ + { TVEEPROM_AUDPROC_MSP, "MSP3435" }, + { TVEEPROM_AUDPROC_MSP, "MSP3440" }, + { TVEEPROM_AUDPROC_MSP, "MSP3445" }, + { TVEEPROM_AUDPROC_MSP, "MSP3411" }, + { TVEEPROM_AUDPROC_MSP, "MSP3416" }, + /* 15-19 */ + { TVEEPROM_AUDPROC_MSP, "MSP3425" }, + { TVEEPROM_AUDPROC_MSP, "MSP3451" }, + { TVEEPROM_AUDPROC_MSP, "MSP3418" }, + { TVEEPROM_AUDPROC_OTHER, "Type 0x12" }, + { TVEEPROM_AUDPROC_OTHER, "OKI7716" }, + /* 20-24 */ + { TVEEPROM_AUDPROC_MSP, "MSP4410" }, + { TVEEPROM_AUDPROC_MSP, "MSP4420" }, + { TVEEPROM_AUDPROC_MSP, "MSP4440" }, + { TVEEPROM_AUDPROC_MSP, "MSP4450" }, + { TVEEPROM_AUDPROC_MSP, "MSP4408" }, + /* 25-29 */ + { TVEEPROM_AUDPROC_MSP, "MSP4418" }, + { TVEEPROM_AUDPROC_MSP, "MSP4428" }, + { TVEEPROM_AUDPROC_MSP, "MSP4448" }, + { TVEEPROM_AUDPROC_MSP, "MSP4458" }, + { TVEEPROM_AUDPROC_MSP, "Type 0x1d" }, + /* 30-34 */ + { TVEEPROM_AUDPROC_INTERNAL, "CX880" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX881" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX883" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX882" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX25840" }, + /* 35-39 */ + { TVEEPROM_AUDPROC_INTERNAL, "CX25841" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX25842" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX25843" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX23418" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX23885" }, + /* 40-44 */ + { TVEEPROM_AUDPROC_INTERNAL, "CX23888" }, + { TVEEPROM_AUDPROC_INTERNAL, "SAA7131" }, + { TVEEPROM_AUDPROC_INTERNAL, "CX23887" }, + { TVEEPROM_AUDPROC_INTERNAL, "SAA7164" }, + { TVEEPROM_AUDPROC_INTERNAL, "AU8522" }, +}; + +/* This list is supplied by Hauppauge. Thanks! */ +static const char *decoderIC[] = { + /* 0-4 */ + "None", "BT815", "BT817", "BT819", "BT815A", + /* 5-9 */ + "BT817A", "BT819A", "BT827", "BT829", "BT848", + /* 10-14 */ + "BT848A", "BT849A", "BT829A", "BT827A", "BT878", + /* 15-19 */ + "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115", + /* 20-24 */ + "CX880", "CX881", "CX883", "SAA7111", "SAA7113", + /* 25-29 */ + "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", + /* 30-34 */ + "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", + /* 35-39 */ + "SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A", + /* 40-42 */ + "SAA7164", "CX23885B", "AU8522" +}; + +static int hasRadioTuner(int tunerType) +{ + switch (tunerType) { + case 18: /* PNPEnv_TUNER_FR1236_MK2 */ + case 23: /* PNPEnv_TUNER_FM1236 */ + case 38: /* PNPEnv_TUNER_FMR1236 */ + case 16: /* PNPEnv_TUNER_FR1216_MK2 */ + case 19: /* PNPEnv_TUNER_FR1246_MK2 */ + case 21: /* PNPEnv_TUNER_FM1216 */ + case 24: /* PNPEnv_TUNER_FM1246 */ + case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ + case 22: /* PNPEnv_TUNER_FM1216MF */ + case 20: /* PNPEnv_TUNER_FR1256_MK2 */ + case 25: /* PNPEnv_TUNER_FM1256 */ + case 33: /* PNPEnv_TUNER_4039FR5 */ + case 42: /* PNPEnv_TUNER_4009FR5 */ + case 52: /* PNPEnv_TUNER_4049FM5 */ + case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ + case 44: /* PNPEnv_TUNER_4009FN5 */ + case 31: /* PNPEnv_TUNER_TCPB9085P */ + case 30: /* PNPEnv_TUNER_TCPN9085D */ + case 46: /* PNPEnv_TUNER_TP18NSR01F */ + case 47: /* PNPEnv_TUNER_TP18PSB01D */ + case 49: /* PNPEnv_TUNER_TAPC_I001D */ + case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ + case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ + case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ + case 58: /* PNPEnv_TUNER_FM1236_MK3 */ + case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ + case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ + case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ + case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ + case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ + case 105: + return 1; + } + return 0; +} + +void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, + unsigned char *eeprom_data) +{ + /* ---------------------------------------------- + ** The hauppauge eeprom format is tagged + ** + ** if packet[0] == 0x84, then packet[0..1] == length + ** else length = packet[0] & 3f; + ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum + ** + ** In our (ivtv) case we're interested in the following: + ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into + ** hauppauge_tuner_fmt) + ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) + ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) + ** decoder proc: tag [09].01) + + ** Fun info: + ** model: tag [00].07-08 or [06].00-01 + ** revision: tag [00].09-0b or [06].04-06 + ** serial#: tag [01].05-07 or [04].04-06 + + ** # of inputs/outputs ??? + */ + + int i, j, len, done, beenhere, tag, start; + + int tuner1 = 0, t_format1 = 0, audioic = -1; + const char *t_name1 = NULL; + const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; + + int tuner2 = 0, t_format2 = 0; + const char *t_name2 = NULL; + const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; + + memset(tvee, 0, sizeof(*tvee)); + tvee->tuner_type = TUNER_ABSENT; + tvee->tuner2_type = TUNER_ABSENT; + + done = len = beenhere = 0; + + /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ + if (eeprom_data[0] == 0x1a && + eeprom_data[1] == 0xeb && + eeprom_data[2] == 0x67 && + eeprom_data[3] == 0x95) + start = 0xa0; /* Generic em28xx offset */ + else if ((eeprom_data[0] & 0xe1) == 0x01 && + eeprom_data[1] == 0x00 && + eeprom_data[2] == 0x00 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx2388x offset */ + else if (eeprom_data[1] == 0x70 && + eeprom_data[2] == 0x00 && + eeprom_data[4] == 0x74 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx23418 offset (models 74xxx) */ + else + start = 0; + + for (i = start; !done && i < 256; i += len) { + if (eeprom_data[i] == 0x84) { + len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); + i += 3; + } else if ((eeprom_data[i] & 0xf0) == 0x70) { + if (eeprom_data[i] & 0x08) { + /* verify checksum! */ + done = 1; + break; + } + len = eeprom_data[i] & 0x07; + ++i; + } else { + tveeprom_warn("Encountered bad packet header [%02x]. " + "Corrupt or not a Hauppauge eeprom.\n", + eeprom_data[i]); + return; + } + + if (debug) { + tveeprom_info("Tag [%02x] + %d bytes:", + eeprom_data[i], len - 1); + for (j = 1; j < len; j++) + printk(KERN_CONT " %02x", eeprom_data[i + j]); + printk(KERN_CONT "\n"); + } + + /* process by tag */ + tag = eeprom_data[i]; + switch (tag) { + case 0x00: + /* tag: 'Comprehensive' */ + tuner1 = eeprom_data[i+6]; + t_format1 = eeprom_data[i+5]; + tvee->has_radio = eeprom_data[i+len-1]; + /* old style tag, don't know how to detect + IR presence, mark as unknown. */ + tvee->has_ir = 0; + tvee->model = + eeprom_data[i+8] + + (eeprom_data[i+9] << 8); + tvee->revision = eeprom_data[i+10] + + (eeprom_data[i+11] << 8) + + (eeprom_data[i+12] << 16); + break; + + case 0x01: + /* tag: 'SerialID' */ + tvee->serial_number = + eeprom_data[i+6] + + (eeprom_data[i+7] << 8) + + (eeprom_data[i+8] << 16); + break; + + case 0x02: + /* tag 'AudioInfo' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + audioic = eeprom_data[i+2] & 0x7f; + if (audioic < ARRAY_SIZE(audio_ic)) + tvee->audio_processor = audio_ic[audioic].id; + else + tvee->audio_processor = TVEEPROM_AUDPROC_OTHER; + break; + + /* case 0x03: tag 'EEInfo' */ + + case 0x04: + /* tag 'SerialID2' */ + tvee->serial_number = + eeprom_data[i+5] + + (eeprom_data[i+6] << 8) + + (eeprom_data[i+7] << 16); + + if ((eeprom_data[i + 8] & 0xf0) && + (tvee->serial_number < 0xffffff)) { + tvee->MAC_address[0] = 0x00; + tvee->MAC_address[1] = 0x0D; + tvee->MAC_address[2] = 0xFE; + tvee->MAC_address[3] = eeprom_data[i + 7]; + tvee->MAC_address[4] = eeprom_data[i + 6]; + tvee->MAC_address[5] = eeprom_data[i + 5]; + tvee->has_MAC_address = 1; + } + break; + + case 0x05: + /* tag 'Audio2' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + audioic = eeprom_data[i+1] & 0x7f; + if (audioic < ARRAY_SIZE(audio_ic)) + tvee->audio_processor = audio_ic[audioic].id; + else + tvee->audio_processor = TVEEPROM_AUDPROC_OTHER; + + break; + + case 0x06: + /* tag 'ModelRev' */ + tvee->model = + eeprom_data[i + 1] + + (eeprom_data[i + 2] << 8) + + (eeprom_data[i + 3] << 16) + + (eeprom_data[i + 4] << 24); + tvee->revision = + eeprom_data[i + 5] + + (eeprom_data[i + 6] << 8) + + (eeprom_data[i + 7] << 16); + break; + + case 0x07: + /* tag 'Details': according to Hauppauge not interesting + on any PCI-era or later boards. */ + break; + + /* there is no tag 0x08 defined */ + + case 0x09: + /* tag 'Video' */ + tvee->decoder_processor = eeprom_data[i + 1]; + break; + + case 0x0a: + /* tag 'Tuner' */ + if (beenhere == 0) { + tuner1 = eeprom_data[i + 2]; + t_format1 = eeprom_data[i + 1]; + beenhere = 1; + } else { + /* a second (radio) tuner may be present */ + tuner2 = eeprom_data[i + 2]; + t_format2 = eeprom_data[i + 1]; + /* not a TV tuner? */ + if (t_format2 == 0) + tvee->has_radio = 1; /* must be radio */ + } + break; + + case 0x0b: + /* tag 'Inputs': according to Hauppauge this is specific + to each driver family, so no good assumptions can be + made. */ + break; + + /* case 0x0c: tag 'Balun' */ + /* case 0x0d: tag 'Teletext' */ + + case 0x0e: + /* tag: 'Radio' */ + tvee->has_radio = eeprom_data[i+1]; + break; + + case 0x0f: + /* tag 'IRInfo' */ + tvee->has_ir = 1 | (eeprom_data[i+1] << 1); + break; + + /* case 0x10: tag 'VBIInfo' */ + /* case 0x11: tag 'QCInfo' */ + /* case 0x12: tag 'InfoBits' */ + + default: + tveeprom_dbg("Not sure what to do with tag [%02x]\n", + tag); + /* dump the rest of the packet? */ + } + } + + if (!done) { + tveeprom_warn("Ran out of data!\n"); + return; + } + + if (tvee->revision != 0) { + tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); + tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); + tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); + tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); + tvee->rev_str[4] = 0; + } + + if (hasRadioTuner(tuner1) && !tvee->has_radio) { + tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); + tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); + tvee->has_radio = 1; + } + + if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) { + tvee->tuner_type = hauppauge_tuner[tuner1].id; + t_name1 = hauppauge_tuner[tuner1].name; + } else { + t_name1 = "unknown"; + } + + if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) { + tvee->tuner2_type = hauppauge_tuner[tuner2].id; + t_name2 = hauppauge_tuner[tuner2].name; + } else { + t_name2 = "unknown"; + } + + tvee->tuner_hauppauge_model = tuner1; + tvee->tuner2_hauppauge_model = tuner2; + tvee->tuner_formats = 0; + tvee->tuner2_formats = 0; + for (i = j = 0; i < 8; i++) { + if (t_format1 & (1 << i)) { + tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; + t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; + } + } + for (i = j = 0; i < 8; i++) { + if (t_format2 & (1 << i)) { + tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; + t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; + } + } + + tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", + tvee->model, tvee->rev_str, tvee->serial_number); + if (tvee->has_MAC_address == 1) + tveeprom_info("MAC address is %pM\n", tvee->MAC_address); + tveeprom_info("tuner model is %s (idx %d, type %d)\n", + t_name1, tuner1, tvee->tuner_type); + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], + t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], + t_fmt_name1[6], t_fmt_name1[7], t_format1); + if (tuner2) + tveeprom_info("second tuner model is %s (idx %d, type %d)\n", + t_name2, tuner2, tvee->tuner2_type); + if (t_format2) + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], + t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], + t_fmt_name2[6], t_fmt_name2[7], t_format2); + if (audioic < 0) { + tveeprom_info("audio processor is unknown (no idx)\n"); + tvee->audio_processor = TVEEPROM_AUDPROC_OTHER; + } else { + if (audioic < ARRAY_SIZE(audio_ic)) + tveeprom_info("audio processor is %s (idx %d)\n", + audio_ic[audioic].name, audioic); + else + tveeprom_info("audio processor is unknown (idx %d)\n", + audioic); + } + if (tvee->decoder_processor) + tveeprom_info("decoder processor is %s (idx %d)\n", + STRM(decoderIC, tvee->decoder_processor), + tvee->decoder_processor); + if (tvee->has_ir) + tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", + tvee->has_radio ? "" : "no ", + (tvee->has_ir & 2) ? "" : "no ", + (tvee->has_ir & 4) ? "" : "no "); + else + tveeprom_info("has %sradio\n", + tvee->has_radio ? "" : "no "); +} +EXPORT_SYMBOL(tveeprom_hauppauge_analog); + +/* ----------------------------------------------------------------------- */ +/* generic helper functions */ + +int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) +{ + unsigned char buf; + int err; + + buf = 0; + err = i2c_master_send(c, &buf, 1); + if (err != 1) { + tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); + return -1; + } + err = i2c_master_recv(c, eedata, len); + if (err != len) { + tveeprom_warn("i2c eeprom read error (err=%d)\n", err); + return -1; + } + if (debug) { + int i; + + tveeprom_info("full 256-byte eeprom dump:\n"); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + tveeprom_info("%02x:", i); + printk(KERN_CONT " %02x", eedata[i]); + if (15 == (i % 16)) + printk(KERN_CONT "\n"); + } + } + return 0; +} +EXPORT_SYMBOL(tveeprom_read); |
